Add BitFullCalendar extras component (#12449)#12450
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughAdds the FullCalendar extras component surface, shared contracts and state, calendar views, timeline layouts, styling, and demo/navigation wiring. ChangesBitFullCalendar feature
Estimated code review effort🎯 5 (Critical) | ⏱️ ~120 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
@coderabbitai re-review |
|
✅ Action performedFull review finished. |
There was a problem hiding this comment.
Actionable comments posted: 1
Note
Due to the large number of review comments, Critical severity comments were prioritized as inline comments.
🟡 Minor comments (11)
src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razor-5-5 (1)
5-5:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winPolish the page description text for user-facing docs.
Current wording is awkward and inconsistent in casing (
"fullcalendar component of the bit BlazorUI components"). Consider a clearer description, e.g. “FullCalendar component for Bit BlazorUI.”🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razor` at line 5, The Description attribute text in the BitFullCalendarDemo.razor component has awkward wording and inconsistent casing. Update the Description property to use proper casing for "FullCalendar" (currently lowercase) and simplify the text to remove redundancy. Instead of "fullcalendar component of the bit BlazorUI components", use clearer phrasing such as "FullCalendar component for Bit BlazorUI" to improve readability and consistency for user-facing documentation.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarHelpers.cs-213-218 (1)
213-218:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winUse active culture for time labels instead of
InvariantCulture.At Line 216 and Line 253, forcing invariant formatting breaks localization consistency for time strings in non-English cultures.
Suggested fix
- public static string FormatTime(DateTime date, bool use24Hour) + public static string FormatTime(DateTime date, bool use24Hour, CultureInfo? culture = null) { + culture ??= CultureInfo.CurrentUICulture; return use24Hour - ? date.ToString("HH:mm", CultureInfo.InvariantCulture) - : date.ToString("h:mm tt", CultureInfo.InvariantCulture); + ? date.ToString("HH:mm", culture) + : date.ToString("h:mm tt", culture); } @@ - public static string FormatHourLabel(int hour, bool use24Hour) + public static string FormatHourLabel(int hour, bool use24Hour, CultureInfo? culture = null) { var dt = DateTime.Today.AddHours(hour); + culture ??= CultureInfo.CurrentUICulture; return use24Hour - ? dt.ToString("HH:00", CultureInfo.InvariantCulture) - : dt.ToString("h tt", CultureInfo.InvariantCulture); + ? dt.ToString("HH:00", culture) + : dt.ToString("h tt", culture); }Also applies to: 248-254
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarHelpers.cs` around lines 213 - 218, The FormatTime method is using CultureInfo.InvariantCulture for both the 24-hour and 12-hour time format calls, which prevents localization for non-English cultures. Replace CultureInfo.InvariantCulture with CultureInfo.CurrentCulture in both date.ToString() calls within the FormatTime method to respect the user's active culture settings. Apply the same fix to the similar time formatting code mentioned in the "Also applies to" section around lines 248-254.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cs-25-27 (1)
25-27:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winTreat midnight
EndDateas exclusive for day-span classification.At Line 25,
IsSingleDayuses directDateequality, so an event like2026-06-20 22:00 -> 2026-06-21 00:00is flagged as multi-day even though it ends at the day boundary.Suggested fix
public class BitFullCalendarEvent { @@ - public bool IsSingleDay => StartDate.Date == EndDate.Date; + private DateTime EndDateForDaySpan => + EndDate.TimeOfDay == TimeSpan.Zero && EndDate > StartDate + ? EndDate.AddTicks(-1) + : EndDate; + + public bool IsSingleDay => StartDate.Date == EndDateForDaySpan.Date; public bool IsMultiDay => !IsSingleDay; public TimeSpan Duration => EndDate - StartDate;🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cs` around lines 25 - 27, The IsSingleDay property at line 25 of BitFullCalendarEvent class does not treat midnight EndDate as exclusive, causing events ending at 00:00 of the next day to be incorrectly classified as multi-day. Fix this by adjusting the Date comparison in the IsSingleDay property to subtract one tick or unit of time from EndDate before comparing dates, ensuring that an EndDate at midnight is treated as the end of the previous day rather than the start of the next day.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarChangeEventArgs.cs-49-49 (1)
49-49:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winMake
Sourcerequired to prevent silent origin misclassification.If omitted,
Sourcedefaults toDialog(enum zero), which can report incorrect origin metadata in emitted change payloads. Mark itrequiredto force explicit assignment.Proposed fix
- public BitFullCalendarChangeSource Source { get; init; } + public required BitFullCalendarChangeSource Source { get; init; }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarChangeEventArgs.cs` at line 49, Add the `required` keyword to the Source property in the BitFullCalendarChangeEventArgs class to force callers to explicitly assign a BitFullCalendarChangeSource value, preventing silent defaults to Dialog (the zero enum value) which can cause incorrect origin metadata in change payloads.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razor-20-23 (1)
20-23:⚠️ Potential issue | 🟡 MinorSet add-event button type explicitly to avoid accidental form submission.
Without
type="button", this button defaults totype="submit"per HTML specification. If the FullCalendar component is used inside a form context, the button will unintentionally trigger form submission instead of only calling theOnAddEventClickhandler. Adding the explicit type prevents this risk.🛠️ Suggested fix
- <button class="bit-bfc-btn bit-bfc-btn-primary bit-bfc-btn-sm" `@onclick`="OnAddEventClick"> + <button type="button" class="bit-bfc-btn bit-bfc-btn-primary bit-bfc-btn-sm" `@onclick`="OnAddEventClick">🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razor` around lines 20 - 23, The button element with the OnAddEventClick handler in BitFcCalendarHeader.razor lacks an explicit type attribute, causing it to default to type="submit" per HTML specification. This can trigger unintended form submission if the FullCalendar component is placed within a form context. Add type="button" explicitly to the button element that contains the OnAddEventClick event handler to ensure it only calls the click handler and does not submit any parent form.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razor-6-6 (1)
6-6:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winUse calendar culture for the dialog date header.
This currently formats with default culture instead of
State.Culture, causing localization inconsistencies.Suggested fix
- <h3>`@Texts.EventListTitlePrefix` `@Date.ToString`("dddd, MMM d, yyyy")</h3> + <h3>`@Texts.EventListTitlePrefix` `@Date.ToString`("dddd, MMM d, yyyy", State.Culture)</h3>🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razor` at line 6, In the BitFcEventListDialog.razor component's h3 element, the date formatting using Date.ToString("dddd, MMM d, yyyy") does not respect the calendar's culture setting. Modify the Date.ToString call to include State.Culture as a culture parameter so that the date is formatted according to the calendar's culture instead of the default culture. This will ensure the date header displays in the correct localized format.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventDetailsDialog.razor.cs-19-23 (1)
19-23:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winAwait
OnClose.InvokeAsync()in the edit-close flow.The callback task is currently not awaited.
Suggested fix
- private void OnEditClose() + private async Task OnEditClose() { _showEdit = false; - OnClose.InvokeAsync(); + await OnClose.InvokeAsync(); }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventDetailsDialog.razor.cs` around lines 19 - 23, The OnEditClose() method invokes the OnClose callback asynchronously but does not await the result, which can cause the callback to not complete properly. Change the OnEditClose() method signature from void to async Task, and add the await keyword before the OnClose.InvokeAsync() call to ensure the asynchronous operation completes before the method returns.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razor.cs-36-49 (1)
36-49:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winKeep
SelectedDateconsistent across both add-event paths.
State.SetSelectedDate(day)is only applied whenOnAddClickis delegated, not when using the built-in add dialog.Suggested fix
private async Task OnHourClickAsync(DateTime day, int hour) { + State.SetSelectedDate(day); + if (OnAddClick.HasDelegate) { - State.SetSelectedDate(day); var draft = BitFullCalendarHelpers.CreateDraftEventForTimeSlot(day, hour); await OnAddClick.InvokeAsync(draft); return; }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razor.cs` around lines 36 - 49, The OnHourClickAsync method only calls State.SetSelectedDate(day) when OnAddClick has a delegate, but not when using the built-in add dialog (when _addDate, _addHour, and _showAddDialog are set). Move the State.SetSelectedDate(day) call outside of the if block so it executes regardless of which path is taken, ensuring the SelectedDate remains consistent across both the delegated callback path and the built-in dialog path.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razor-8-10 (1)
8-10:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winUse calendar month count instead of hardcoded 12.
Line 8 should use the active calendar’s month count (
GetMonthsInYear) to avoid incorrect year rendering in calendars that don’t match a fixed 12-month assumption.Proposed fix
- var months = Enumerable.Range(1, 12) + var monthsInYear = cal.GetMonthsInYear(culturalYear); + var months = Enumerable.Range(1, monthsInYear) .Select(m => cal.ToDateTime(culturalYear, m, 1, 0, 0, 0, 0)) .ToArray();🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razor` around lines 8 - 10, Replace the hardcoded value 12 in the Enumerable.Range call within the months variable assignment with a dynamic call to the calendar's month count method. Instead of Range(1, 12), use Range(1, cal.GetMonthsInYear(culturalYear)) or the appropriate equivalent method on the cal object to retrieve the actual number of months in the given year, ensuring the code correctly handles calendars with varying month counts.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razor-79-80 (1)
79-80:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winDrop preview can stick after drag cancellation.
Preview class application should be tied to active drag state; otherwise stale highlights can remain after drag ends outside a drop target.
Suggested fix
- var isPreview = _dragResourceId == rowKey && _dragDay == day.Date; + var isPreview = State.IsDragging && _dragResourceId == rowKey && _dragDay == day.Date; ... - var isPreview = _dragResourceId == rowKey && _dragDay == day.Date; + var isPreview = State.IsDragging && _dragResourceId == rowKey && _dragDay == day.Date;Also applies to: 106-107
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razor` around lines 79 - 80, The isPreview condition on lines 79-80 (and also on lines 106-107) only checks if the current cell matches the drag source cell, but does not verify if an active drag operation is in progress. When a drag is cancelled, these variables retain their values, causing stale preview highlights to remain. Add a check for an active drag state (such as a boolean flag tracking whether a drag is currently in progress) to the isPreview condition so that the preview class is only applied when there is both an active drag operation and the cell matches the drag source.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razor-60-61 (1)
60-61:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winDrop preview can remain visible after drag cancel/end.
Preview styling is computed without checking active drag state, so a canceled drag can leave stale highlighted cells.
Suggested fix
- var isPreviewHour = _dragResourceId == rowKey && _dragHour == hour && _dragMinute == 0; - var isPreviewHalf = _dragResourceId == rowKey && _dragHour == hour && _dragMinute == 30; + var isPreviewHour = State.IsDragging && _dragResourceId == rowKey && _dragHour == hour && _dragMinute == 0; + var isPreviewHalf = State.IsDragging && _dragResourceId == rowKey && _dragHour == hour && _dragMinute == 30; ... - var isPreviewHour = _dragResourceId == rowKey && _dragHour == hour && _dragMinute == 0; - var isPreviewHalf = _dragResourceId == rowKey && _dragHour == hour && _dragMinute == 30; + var isPreviewHour = State.IsDragging && _dragResourceId == rowKey && _dragHour == hour && _dragMinute == 0; + var isPreviewHalf = State.IsDragging && _dragResourceId == rowKey && _dragHour == hour && _dragMinute == 30;Also applies to: 95-96
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razor` around lines 60 - 61, The preview styling for drag operations in BitFcTimelineDayView.razor is computed without verifying that an active drag is in progress, allowing stale preview highlighting to persist after a drag is canceled. Add a check to verify that a drag operation is currently active before setting isPreviewHour and isPreviewHalf variables around lines 60-61. Additionally, apply the same fix to the similar preview checks mentioned at lines 95-96. The condition should verify that _dragResourceId is not null or empty and that an active drag state exists before allowing the preview styles to be applied.
🧹 Nitpick comments (2)
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorScheme.cs (1)
90-101: 🏗️ Heavy liftUse deterministic lexical fallback for unknown color IDs.
Line 101 uses a hash-based fallback, which does not implement “unknown ids by name” and can reorder groups between process runs. Prefer a stable secondary textual key at sort callsites (e.g.,
ThenBy(colorId, OrdinalIgnoreCase)).🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorScheme.cs` around lines 90 - 101, The GetSortOrder method in BitFullCalendarColorScheme currently uses StringComparer.OrdinalIgnoreCase.GetHashCode() for unknown color IDs, which is non-deterministic across process runs and doesn't implement text-based sorting as documented. Replace the hash-based fallback on line 101 with a deterministic approach that sorts unknown IDs lexically by their string value instead of relying on hash codes, such as computing a value based on the ordinal character values of the trimmed string or implementing a stable text-based comparison alternative.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razor (1)
11-16: ⚡ Quick winPre-index week events to avoid repeated linear scans in render.
At Line 14,
FirstOrDefaultover_weekEventsruns inside nested day/row loops, which makes rerenders grow quadratically with event volume. Precompute a(day,row) -> eventlookup inOnParametersSetand render with O(1) lookups.♻️ Proposed optimization
--- a/src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razor.cs +++ b/src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razor.cs @@ - private Dictionary<string, int> _eventRows = new(); + private Dictionary<string, int> _eventRows = new(); + private Dictionary<(DateTime Day, int Row), BitFullCalendarEvent> _weekEventsByDayRow = new(); @@ - _eventRows = new Dictionary<string, int>(); + _eventRows = new Dictionary<string, int>(); + _weekEventsByDayRow = new(); @@ - foreach (var d in evDays) - rowUsageByDay[d.Date].Add(row); + foreach (var d in evDays) + { + var day = d.Date; + rowUsageByDay[day].Add(row); + _weekEventsByDayRow[(day, row)] = ev; + } break; } } }--- a/src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razor +++ b/src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razor @@ - var ev = _weekEvents.FirstOrDefault(e => - _eventRows.GetValueOrDefault(e.Id) == r && - e.StartDate.Date <= d.Date && e.EndDate.Date >= d.Date); + _weekEventsByDayRow.TryGetValue((d.Date, r), out var ev);🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razor` around lines 11 - 16, The FirstOrDefault call over _weekEvents is executed inside nested loops for each day and row, causing quadratic time complexity during rerenders. Create a precomputed lookup dictionary in the OnParametersSet lifecycle method that maps (date, row) tuples to events based on the same filtering criteria (checking _eventRows values and date ranges with StartDate.Date and EndDate.Date comparisons). Then replace the FirstOrDefault logic in the render loop with a simple O(1) dictionary lookup using the current day and row as the key.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razor.cs`:
- Around line 8-21: The RemoveAfterDelay method mutates _toasts without
dispatcher protection on line 19, creating a race condition with the Razor
template's foreach loop. Additionally, delayed removal tasks are never canceled
when the component is disposed. To fix this, wrap the _toasts.RemoveAll() call
inside RemoveAfterDelay with InvokeAsync() to ensure it runs on the renderer
dispatcher. Next, create a collection to track CancellationTokenSource objects
for each delayed removal task, modify RemoveAfterDelay to accept a
CancellationToken and check it after the Task.Delay, and implement
IAsyncDisposable on the component class to cancel all pending removal tasks when
the component is disposed.
---
Major comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.razor.cs`:
- Around line 156-159: The ResolveCulture() method in BitFullCalendar.razor.cs
attempts to instantiate CultureInfo with a user-provided name without handling
potential exceptions. Wrap the CultureInfo(name) constructor call in a try-catch
block that catches CultureNotFoundException and falls back to the default
culture (Culture ?? CultureInfo.CurrentUICulture) when an invalid culture name
is provided. This prevents the component initialization from failing due to
invalid CultureName parameter values.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.scss`:
- Line 3: Remove the `.scss` file extension from the import statement in the
BitFullCalendar.scss file. The import path for the functions partial currently
includes `functions.scss` but should be changed to `functions` (without the
extension) to comply with the scss/load-partial-extension linting rule. Update
the import statement to remove the `.scss` extension while keeping the relative
path and quotes intact.
- Line 197: The keyframe names bfcFadeIn and bfcSlideUp are using camelCase
naming, which violates the stylelint keyframes-name-pattern rule that requires
kebab-case. Rename bfcFadeIn to bfc-fade-in and bfcSlideUp to bfc-slide-up in
both their keyframe definitions (where they are declared with `@keyframes`) and in
all animation property references throughout the BitFullCalendar.scss file.
Ensure all 8 occurrences are updated consistently to use the kebab-case format.
In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.ts`:
- Around line 113-134: In the endResize function, the OnResizeEnd call must
always execute even if the OnResizeMove invocation fails. Wrap the await
dotNetRef.invokeMethodAsync call for OnResizeMove in a try-finally block, and
move the await dotNetRef.invokeMethodAsync call for OnResizeEnd into the finally
block to guarantee it always executes regardless of whether the OnResizeMove
call succeeds or throws an error. Apply the same fix to the corresponding
endResize function in the other section mentioned at lines 183-204.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcAddEditEventDialog.razor`:
- Around line 16-17: Labels in the BitFcAddEditEventDialog component are not
programmatically associated with their corresponding input controls, which
breaks accessibility for screen readers. Add a unique id attribute to each input
element (the text inputs near the TitleLabel, and other form fields at lines
25-26, 30-31, 39-40, 49-50, and 76-79), then add a for attribute to each label
element that matches the id of its paired input. For example, add
id="_titleInput" to the input with `@bind`="_title" and add for="_titleInput" to
the label for TitleLabel.
- Around line 68-70: The attendee remove button at line 68 is an icon-only
button without an accessible label, which makes it unclear to assistive
technologies. Add an aria-label attribute to the button element that calls
RemoveAttendee(attendee) to provide a descriptive accessible name such as
"Remove attendee" or "Remove [attendee name]" so screen readers can properly
announce the button's purpose to users.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razor.cs`:
- Around line 71-74: The OnFocusOut method closes the picker unconditionally
whenever any internal element loses focus, causing the picker to close when
focus moves between internal controls like the trigger button and time/day
controls. Modify the OnFocusOut method to check whether focus is moving to
another element within the component container before closing the picker. You
should verify if the newly focused element (accessible through FocusEventArgs or
related properties) is still a child of the component, and only set _isOpen to
false when focus actually leaves the entire component bounds.
- Around line 54-57: In the SelectDate method, the new DateTime being
constructed uses date.Kind as the DateTimeKind parameter, which can
inadvertently downgrade a previously set Utc or Local kind to Unspecified. To
preserve the bound DateTimeKind, replace date.Kind with Value.Kind when
constructing the selected DateTime object, ensuring the original kind property
is maintained throughout the selection process.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcDateNavigator.razor`:
- Around line 4-11: The icon-only navigation buttons using
State.NavigatePrevious and State.NavigateNext rely only on the title attribute
for accessibility, which may not be consistently announced by assistive
technologies. Add aria-label attributes to both buttons with descriptive text
matching the button's purpose (e.g., "Previous" and "Next"), and also add
type="button" to both button elements to ensure they are semantically correct
and properly recognized by assistive technologies.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razor`:
- Around line 8-19: The entire mode tabs container in BitFcModeTabs.razor is
hidden when State.Resources.Count is zero, which traps users in Timeline mode if
resources become empty since they have no UI way to switch back to Event mode.
Remove the outer conditional check on State.Resources.Count so that the mode
tabs remain visible even when resources are empty. Keep the tabs accessible at
all times by rendering the entire div with the foreach loop over _modes and the
State.SetMode(mode) calls regardless of whether State.Resources has items.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razor`:
- Around line 12-47: The checkbox inputs in the three dropdown items (for badge
variant toggle, time format toggle, and event layout toggle) and the number
input for day start hour lack proper accessible associations with their labels.
Add unique `id` attributes to each input element (the three checkboxes and the
number input), then update the `label` elements wrapping the checkboxes to
include `for` attributes referencing their corresponding input ids, and for the
number input that doesn't have a wrapping label, add an `aria-labelledby`
attribute that references the id of the span containing DayStartsAtLabel text to
establish the semantic relationship for screen readers.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorScheme.cs`:
- Around line 20-28: The constructor in BitFullCalendarColorScheme keeps a live
reference to the caller-provided options list on line 21 by directly assigning
it to the Options property, while the _byId dictionary is built only once during
construction. If the source list is mutated after construction, Options and the
_byId lookup dictionary can become inconsistent. To fix this, create a defensive
copy/snapshot of the options list (using ToList() or similar) before assigning
it to Options, ensuring that both Options and _byId always represent the same
immutable state regardless of external mutations to the original list.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcAgendaScrollInterop.cs`:
- Line 19: The date.ToString("yyyy-MM-dd") call on the date variable is
culture-sensitive and may produce non-ASCII digits in certain locales, which
will break JavaScript date matching and parsing. Modify the ToString call to
explicitly use CultureInfo.InvariantCulture as the second parameter to ensure
the date is always formatted with ASCII digits in the yyyy-MM-dd format,
regardless of the system locale.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarChangeNotifier.cs`:
- Around line 68-82: The CloneEvent method in BitFullCalendarChangeNotifier
performs a shallow copy of the Data property by directly assigning the reference
instead of creating a deep clone, which violates the deep-snapshot contract.
Modify the Data assignment in the CloneEvent method to deep clone the
source.Data object rather than copying the reference, using an appropriate deep
cloning mechanism such as JSON serialization and deserialization to ensure
mutable objects are not shared between the original and cloned event payloads.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarState.cs`:
- Around line 178-186: The EventsMatch method is using reference equality checks
only, which means when parent components modify existing event instances without
changing the reference, SyncEvents skips the update thinking nothing changed.
Update the EventsMatch method to perform deep content-based comparison of the
event properties instead of just ReferenceEquals checks, so that mutations to
existing items are properly detected. Apply the same fix to the SyncResources
method and its corresponding ResourcesMatch comparison method to ensure
consistent behavior across both event and resource synchronization.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razor.cs`:
- Around line 3-90: The BitFcCalendarDayView component displays current events
based on DateTime.Now but never triggers periodic re-renders, causing the
"Happening now" status to become stale during long sessions. Add a timer
mechanism in the component lifecycle (such as in OnInitializedAsync or
OnAfterRenderAsync) that periodically calls StateHasChanged() at regular
intervals (e.g., every minute) to refresh the component and keep the current
event status accurate. Ensure the timer is properly disposed in the component's
cleanup to prevent memory leaks, similar to how the scroll signature is managed
in the existing lifecycle methods.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razor.cs`:
- Around line 13-17: In the timer callback initialization for _timer, both
UpdatePosition() and StateHasChanged() must be wrapped inside a single
InvokeAsync call to ensure they execute on the Blazor renderer thread. Currently
UpdatePosition() is called directly on the timer thread before being marshaled,
which can cause race conditions since _positionPx is modified. Move the
UpdatePosition() call inside the InvokeAsync delegate so that both methods
execute atomically on the renderer thread, preventing state modification outside
the renderer's synchronization context.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razor`:
- Around line 43-47: The week time slot divs with class bit-bfc-hour-row are
currently only clickable, which excludes keyboard users. Add a keyboard event
handler by binding `@onkeydown` to a new method (OnHourSlotKeyDownAsync) that
accepts KeyboardEventArgs along with the day and hour parameters, and invoke the
existing OnHourClickAsync method when the Enter or Space keys are pressed. Apply
this keyboard handler binding to both affected div elements in the week view
grid (the ones currently showing `@onclick`="() => OnHourClickAsync(d, hour)").
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razor`:
- Around line 28-35: The BitFcEventBlock event container div is not
keyboard-accessible, preventing keyboard users from activating event details.
Add the tabindex="0" attribute to the div element to make it focusable, then add
the `@onkeydown`="OnKeyDown" event binding to the same div. Implement the
OnKeyDown method that takes KeyboardEventArgs as a parameter and calls the
existing OnClick method when the user presses Enter or Space keys.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razor`:
- Around line 15-21: The icon-only buttons for PrevMonth and NextMonth
navigation lack accessible labels for screen readers, making them inaccessible.
Add aria-label attributes to both buttons with descriptive text like "Previous
month" and "Next month" respectively. Additionally, the day selection elements
(the clickable span elements referenced at lines 43-45) need keyboard support -
convert them to button elements or add keyboard event handlers (onkeydown) to
make them accessible via keyboard navigation, ensuring they can be focused and
activated with Enter/Space keys like standard controls.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razor.cs`:
- Around line 9-15: The `_displayMonth` field is initialized only once in
`OnInitialized()` and can become out of sync with `State.SelectedDate` when the
selected date changes externally. Override the `OnParametersSet()` lifecycle
method in the BitFcMiniCalendar component to synchronize `_displayMonth`
whenever parameters change, using the same logic that calculates `_displayMonth`
from `State.SelectedDate` as in `OnInitialized()`. This ensures `_displayMonth`
stays synchronized with external changes to the selected date.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcDayCell.razor`:
- Around line 8-12: The clickable div elements in the BitFcDayCell component
(around line 8 with the OnCellClick handler and the additional clickable element
around line 44) do not support keyboard navigation and activation, making them
inaccessible to keyboard users. Convert these interactive divs to proper
keyboard-accessible controls by adding a tabindex attribute to make them
focusable, an ARIA role to identify them as interactive elements, and keyboard
event handlers (`@onkeydown` or `@onkeyup`) that trigger the same OnCellClick action
when Enter or Space keys are pressed, matching the click behavior.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcMonthEventBadge.razor`:
- Around line 19-25: The BitFcMonthEventBadge component's event badge div is not
keyboard-accessible. Add tabindex="0" to the div element to make it focusable,
and add an `@onkeydown` event handler that detects Enter or Space key presses and
invokes OnSelected.InvokeAsync(Event) when those keys are pressed, matching the
behavior of the existing click handler for keyboard users.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razor.cs`:
- Line 18: The constant _scrollContainerId in the BitFcTimelineDayView component
uses a fixed DOM id that can collide when multiple calendar instances render on
the same page. Change _scrollContainerId from a constant to an instance field
that generates a unique identifier per component instance (such as using a GUID
or unique suffix), ensuring each calendar instance has its own unique scroll
container id to prevent the scrollTimelineToTarget method from operating on the
wrong element.
- Around line 72-85: The OnSlotClickAsync method accepts a minute parameter but
discards it in the internal add flow when OnAddClick is not delegated. Store the
minute value by adding a field similar to _addStartHour (for example,
_addStartMinute), then assign the minute parameter to this field when setting
_showAddDialog to true. Next, pass this stored minute value to the
BitFcAddEditEventDialog component by updating its parameters, and ensure the
dialog component supports and respects the minute parameter when initializing
the time selection to preserve half-hour slot precision.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razor.cs`:
- Around line 71-74: The catch block in BitFcTimelineEventBlock.razor.cs
currently only catches JSException, but common Blazor lifecycle exceptions like
JSDisconnectedException, InvalidOperationException, and
OperationCanceledException can also be thrown during interop calls and will
crash the render if not handled. Expand the catch clause to handle all these
exception types alongside JSException so they are properly swallowed and the
render retry logic is executed for all expected failure scenarios.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineLayout.razor`:
- Around line 23-27: The `!hasResources` conditional in
BitFcTimelineLayout.razor prevents the rendering of unassigned event rows
because the else block never executes when hasResources is false. Restructure
the logic to ensure that the unassigned-row rendering (referenced at lines
58-70) is not blocked by the !hasResources check. Either move the unassigned row
rendering outside of or before the hasResources conditional, or add a separate
condition that allows unassigned events to display independently of whether
resources exist.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razor.cs`:
- Line 18: The _scrollContainerId constant in BitFcTimelineMonthView is
hardcoded, causing ID collisions when multiple calendar instances are rendered.
Replace the const declaration with a property or field that generates a unique
identifier per component instance (such as using a Guid or unique prefix based
on component state), ensuring each rendered timeline month view has a distinct
scroll container id that won't conflict with other instances on the same page.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razor`:
- Around line 21-26: The code filters out null/empty resource IDs on line 21,
but then uses unguarded dictionary lookups with resource.Id and rowKey as keys
on lines 60, 91, and 126 without verifying they are not null or empty. Add guard
conditions before each dictionary lookup at these locations to check if the
resource ID or rowKey is null or empty, and either skip the operation or provide
a safe fallback to prevent runtime exceptions when rendering rows with invalid
resource identifiers.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razor.cs`:
- Line 18: The constant _scrollContainerId with a hardcoded value
"bit-bfc-tl-week-scroll" will cause id collisions when multiple calendar
instances are rendered on the same page. Replace this constant with a
per-instance field that generates a unique scroll container id for each
BitFcTimelineWeekView component instance, such as using a generated guid or
unique identifier that is assigned when the component initializes.
- Around line 74-87: The OnSlotClickAsync method receives a minute parameter but
only uses it when OnAddClick has a delegate. In the fallback branch where the
built-in add dialog is shown (lines 84-86), the minute value is ignored. Store
the minute parameter in a new field (similar to how _addStartHour stores the
hour) such as _addStartMinute, and ensure this field is set when _showAddDialog
is set to true. Additionally, verify that the BitFcAddEditEventDialog component
uses this _addStartMinute field when initializing the event time, adding support
for StartMinute if it does not currently exist.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razor`:
- Around line 21-22: The div elements with click handlers at lines 21-22 and
40-41 in BitFcCalendarYearView.razor lack keyboard accessibility, preventing
keyboard-only users from navigating. Add keyboard event support to both div
elements by implementing an onkeydown event handler that triggers the same
action (GoToMonth call at line 21 and the day/event navigation at line 40) when
Enter or Space keys are pressed. Additionally, add appropriate ARIA attributes
(role and tabindex) to make these divs focusable and semantically indicate they
are interactive elements to assistive technologies.
- Around line 37-38: The dayEvents filter in BitFcCalendarYearView.razor uses
only StartDate.Date comparison, which excludes multi-day events from
intermediate and end dates. Modify the Where clause to check if cell.Date falls
within a date-range overlap by comparing against both the event's StartDate and
EndDate properties, ensuring a multi-day event is included on every day it
spans, not just its start date.
In `@src/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scss`:
- Line 7: The stylelint rule scss/load-partial-extension is being violated in
the extra-components.scss file. Remove the explicit .scss file extension from
the `@import` statement for BitFullCalendar - the stylelint rule requires that
SCSS partials be imported without their file extension, so the import should
reference only the directory path and filename without the .scss suffix.
In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razor`:
- Around line 18-23: The BitLink component in BitFullCalendarDemo.razor has
Target="_blank" set to open an external link in a new tab, but it is missing the
rel attribute required for security. Add rel="noopener noreferrer" to the
BitLink component that points to the NuGet package URL to prevent
reverse-tabnabbing vulnerabilities and properly isolate the opener context when
opening external links in a new tab.
---
Minor comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventDetailsDialog.razor.cs`:
- Around line 19-23: The OnEditClose() method invokes the OnClose callback
asynchronously but does not await the result, which can cause the callback to
not complete properly. Change the OnEditClose() method signature from void to
async Task, and add the await keyword before the OnClose.InvokeAsync() call to
ensure the asynchronous operation completes before the method returns.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razor`:
- Line 6: In the BitFcEventListDialog.razor component's h3 element, the date
formatting using Date.ToString("dddd, MMM d, yyyy") does not respect the
calendar's culture setting. Modify the Date.ToString call to include
State.Culture as a culture parameter so that the date is formatted according to
the calendar's culture instead of the default culture. This will ensure the date
header displays in the correct localized format.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razor`:
- Around line 20-23: The button element with the OnAddEventClick handler in
BitFcCalendarHeader.razor lacks an explicit type attribute, causing it to
default to type="submit" per HTML specification. This can trigger unintended
form submission if the FullCalendar component is placed within a form context.
Add type="button" explicitly to the button element that contains the
OnAddEventClick event handler to ensure it only calls the click handler and does
not submit any parent form.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarChangeEventArgs.cs`:
- Line 49: Add the `required` keyword to the Source property in the
BitFullCalendarChangeEventArgs class to force callers to explicitly assign a
BitFullCalendarChangeSource value, preventing silent defaults to Dialog (the
zero enum value) which can cause incorrect origin metadata in change payloads.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cs`:
- Around line 25-27: The IsSingleDay property at line 25 of BitFullCalendarEvent
class does not treat midnight EndDate as exclusive, causing events ending at
00:00 of the next day to be incorrectly classified as multi-day. Fix this by
adjusting the Date comparison in the IsSingleDay property to subtract one tick
or unit of time from EndDate before comparing dates, ensuring that an EndDate at
midnight is treated as the end of the previous day rather than the start of the
next day.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarHelpers.cs`:
- Around line 213-218: The FormatTime method is using
CultureInfo.InvariantCulture for both the 24-hour and 12-hour time format calls,
which prevents localization for non-English cultures. Replace
CultureInfo.InvariantCulture with CultureInfo.CurrentCulture in both
date.ToString() calls within the FormatTime method to respect the user's active
culture settings. Apply the same fix to the similar time formatting code
mentioned in the "Also applies to" section around lines 248-254.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razor.cs`:
- Around line 36-49: The OnHourClickAsync method only calls
State.SetSelectedDate(day) when OnAddClick has a delegate, but not when using
the built-in add dialog (when _addDate, _addHour, and _showAddDialog are set).
Move the State.SetSelectedDate(day) call outside of the if block so it executes
regardless of which path is taken, ensuring the SelectedDate remains consistent
across both the delegated callback path and the built-in dialog path.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razor`:
- Around line 60-61: The preview styling for drag operations in
BitFcTimelineDayView.razor is computed without verifying that an active drag is
in progress, allowing stale preview highlighting to persist after a drag is
canceled. Add a check to verify that a drag operation is currently active before
setting isPreviewHour and isPreviewHalf variables around lines 60-61.
Additionally, apply the same fix to the similar preview checks mentioned at
lines 95-96. The condition should verify that _dragResourceId is not null or
empty and that an active drag state exists before allowing the preview styles to
be applied.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razor`:
- Around line 79-80: The isPreview condition on lines 79-80 (and also on lines
106-107) only checks if the current cell matches the drag source cell, but does
not verify if an active drag operation is in progress. When a drag is cancelled,
these variables retain their values, causing stale preview highlights to remain.
Add a check for an active drag state (such as a boolean flag tracking whether a
drag is currently in progress) to the isPreview condition so that the preview
class is only applied when there is both an active drag operation and the cell
matches the drag source.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razor`:
- Around line 8-10: Replace the hardcoded value 12 in the Enumerable.Range call
within the months variable assignment with a dynamic call to the calendar's
month count method. Instead of Range(1, 12), use Range(1,
cal.GetMonthsInYear(culturalYear)) or the appropriate equivalent method on the
cal object to retrieve the actual number of months in the given year, ensuring
the code correctly handles calendars with varying month counts.
In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razor`:
- Line 5: The Description attribute text in the BitFullCalendarDemo.razor
component has awkward wording and inconsistent casing. Update the Description
property to use proper casing for "FullCalendar" (currently lowercase) and
simplify the text to remove redundancy. Instead of "fullcalendar component of
the bit BlazorUI components", use clearer phrasing such as "FullCalendar
component for Bit BlazorUI" to improve readability and consistency for
user-facing documentation.
---
Nitpick comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorScheme.cs`:
- Around line 90-101: The GetSortOrder method in BitFullCalendarColorScheme
currently uses StringComparer.OrdinalIgnoreCase.GetHashCode() for unknown color
IDs, which is non-deterministic across process runs and doesn't implement
text-based sorting as documented. Replace the hash-based fallback on line 101
with a deterministic approach that sorts unknown IDs lexically by their string
value instead of relying on hash codes, such as computing a value based on the
ordinal character values of the trimmed string or implementing a stable
text-based comparison alternative.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razor`:
- Around line 11-16: The FirstOrDefault call over _weekEvents is executed inside
nested loops for each day and row, causing quadratic time complexity during
rerenders. Create a precomputed lookup dictionary in the OnParametersSet
lifecycle method that maps (date, row) tuples to events based on the same
filtering criteria (checking _eventRows values and date ranges with
StartDate.Date and EndDate.Date comparisons). Then replace the FirstOrDefault
logic in the render loop with a simple O(1) dictionary lookup using the current
day and row as the key.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: e0daf90b-d30d-468a-b05d-3f9abc65f4a8
📒 Files selected for processing (100)
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarBody.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarBody.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.scsssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcAddEditEventDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcAddEditEventDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventDetailsDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventDetailsDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarAgendaGroupBy.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarBadgeVariant.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarEventLayout.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarMode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarView.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcDateNavigator.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcDateNavigator.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcFilterEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcFilterEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcTodayButton.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcTodayButton.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcViewTabs.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcViewTabs.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarAttendee.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarCell.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarChangeEventArgs.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorOption.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorScheme.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarDateChangeEventArgs.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarOptions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarResource.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarTexts.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcAgendaScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcTimeGridScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcTimelineScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarChangeNotifier.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarHelpers.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarState.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcDayViewMultiDayEventsRow.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcDayViewMultiDayEventsRow.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcRenderGroupedEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcRenderGroupedEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcTimeColumn.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcTimeColumn.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcCalendarMonthView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcCalendarMonthView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcDayCell.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcDayCell.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcEventBullet.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcEventBullet.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcMonthEventBadge.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcMonthEventBadge.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineLayout.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineLayout.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scsssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razor.cssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/ComponentsSection.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/MainLayout.razor.NavItems.cs
|
@coderabbitai re-review |
|
✅ Action performedFull review finished. |
There was a problem hiding this comment.
Actionable comments posted: 20
Note
Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.
🟡 Minor comments (6)
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarOptions.cs-16-17 (1)
16-17:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winValidate
StartOfDayHouragainst the documented 0–16 range.Line 17 accepts any integer even though the public contract documents 0–16, and the value is applied directly in
BitFullCalendar.razor.cs(Lines 199-210). Add clamping or validation to prevent out-of-range runtime behavior.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarOptions.cs` around lines 16 - 17, The StartOfDayHour property in BitFullCalendarOptions class lacks validation for the documented 0-16 range constraint, allowing any integer value to be set. This causes runtime issues when the unconstrained value is applied in BitFullCalendar.razor.cs. Add validation logic to the StartOfDayHour property setter to enforce the 0-16 range by either clamping the value using Math.Clamp or throwing an ArgumentException if an out-of-range value is provided, ensuring the property contract matches its documentation.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarHelpers.cs-83-87 (1)
83-87:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winUse current UI culture when
cultureis omitted inStartOfWeek.Line 85 falls back to
DayOfWeek.Sundayinstead ofCultureInfo.CurrentUICulture, which makes this helper inconsistent with other culture-aware methods and can produce incorrect week boundaries for callers that passnull.Suggested fix
public static DateTime StartOfWeek(DateTime date, CultureInfo? culture = null) { - var startDay = culture?.DateTimeFormat.FirstDayOfWeek ?? DayOfWeek.Sunday; + culture ??= CultureInfo.CurrentUICulture; + var startDay = culture.DateTimeFormat.FirstDayOfWeek; return StartOfWeek(date, startDay); }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarHelpers.cs` around lines 83 - 87, The StartOfWeek method currently falls back to DayOfWeek.Sunday when the culture parameter is null, instead of using the current UI culture. Modify the startDay assignment in the StartOfWeek method to use CultureInfo.CurrentUICulture.DateTimeFormat.FirstDayOfWeek as the fallback instead of DayOfWeek.Sunday. This will make the method consistent with other culture-aware methods and properly respect regional week start conventions when no culture is explicitly provided.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razor-4-7 (1)
4-7:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winPrevent browser default behavior on drop.
dropshould also prevent default to avoid accidental browser navigation/content handling on external drops.Suggested fix
<div class="bit-bfc-droppable @(_isOver ? "drag-over" : "") `@Class`" `@ondragover`="OnDragOver" `@ondragover`:preventDefault="true" `@ondragleave`="OnDragLeave" - `@ondrop`="OnDrop"> + `@ondrop`="OnDrop" + `@ondrop`:preventDefault="true">🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razor` around lines 4 - 7, The `@ondrop` event binding in the BitFcDroppableArea component is missing the preventDefault directive that is already applied to `@ondragover`. Add the :preventDefault="true" modifier to the `@ondrop` binding (similar to how it is applied to `@ondragover`) to ensure the browser's default behavior is prevented when items are dropped on the droppable area, avoiding accidental navigation or unwanted content handling from external drops.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razor-13-14 (1)
13-14:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winSet explicit button type to prevent accidental form submission.
These mode-tab buttons should be
type="button"; otherwise default submit behavior can fire when the calendar is placed inside a form.Suggested patch
- <button class="bit-bfc-mode-tab @(State.Mode == mode ? "active" : "")" + <button type="button" class="bit-bfc-mode-tab @(State.Mode == mode ? "active" : "")" `@onclick`="() => State.SetMode(mode)">🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razor` around lines 13 - 14, Add an explicit type="button" attribute to the button element with class "bit-bfc-mode-tab" to prevent it from defaulting to type submit and causing accidental form submissions when the calendar component is placed within a form. This ensures the button only triggers the onclick handler without submitting any parent form.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razor.cs-12-23 (1)
12-23:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winAlign the first timer tick to the next minute boundary.
Line 22 schedules the first refresh exactly 60 seconds after init, which can keep the “current time” marker one minute behind clock boundaries. Aligning initial due-time to the next minute makes updates accurate on
HH:mmtransitions.Suggested fix
protected override void OnInitialized() { UpdatePosition(); + var now = DateTime.Now; + var due = TimeSpan.FromMinutes(1) + - TimeSpan.FromSeconds(now.Second) + - TimeSpan.FromMilliseconds(now.Millisecond); + if (due <= TimeSpan.Zero) due = TimeSpan.FromMinutes(1); + _timer = new Timer(_ => { // Run both the state mutation and the re-render on the renderer's dispatcher so // _positionPx is never modified outside the synchronization context. InvokeAsync(() => { UpdatePosition(); StateHasChanged(); }); - }, null, TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1)); + }, null, due, TimeSpan.FromMinutes(1)); }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razor.cs` around lines 12 - 23, The Timer in the BitFcCalendarTimeline component is configured with an initial due time of one minute, which causes the first refresh to occur one minute after initialization rather than at the next minute boundary. This misalignment can leave the "current time" marker behind by up to 60 seconds. Calculate the time remaining until the next minute boundary by finding the current time's seconds and milliseconds, then subtracting from one minute, and use this calculated TimeSpan as the dueTime parameter in the Timer constructor instead of TimeSpan.FromMinutes(1), keeping TimeSpan.FromMinutes(1) as the period for subsequent ticks. This ensures UpdatePosition is called at clock minute transitions rather than arbitrary intervals.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razor.cs-115-121 (1)
115-121:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winAvoid repeated scroll interop when selected month is not the current month.
When no “today” target exists, this path retries JS interop every render. Add a month guard and cache the signature to prevent unnecessary calls.
Proposed change
protected override async Task OnAfterRenderAsync(bool firstRender) { var sig = $"{State.SelectedDate:yyyy-MM}|{DateTime.Today:yyyy-MM-dd}"; if (sig == _scrollSignature) return; + var cal = State.Culture.Calendar; + var today = DateTime.Today; + var selectedYear = cal.GetYear(State.SelectedDate); + var selectedMonth = cal.GetMonth(State.SelectedDate); + var todayYear = cal.GetYear(today); + var todayMonth = cal.GetMonth(today); + if (selectedYear != todayYear || selectedMonth != todayMonth) + { + _scrollSignature = sig; + return; + } + if (await BitFcTimelineScrollInterop.TryScrollToTargetAsync(JS, _scrollContainerId)) _scrollSignature = sig; }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razor.cs` around lines 115 - 121, The OnAfterRenderAsync method calls BitFcTimelineScrollInterop.TryScrollToTargetAsync on every render even when the selected month is not the current month, resulting in unnecessary JavaScript interop calls since there is no "today" target to scroll to in those cases. Add a guard condition before calling BitFcTimelineScrollInterop.TryScrollToTargetAsync that checks whether State.SelectedDate (year and month) matches DateTime.Today (year and month), so the interop only executes when the selected month is the current month. Keep the existing _scrollSignature caching logic to prevent duplicate calls within the same month.
🧹 Nitpick comments (4)
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarView.cs (1)
3-10: ⚡ Quick winAdd XML documentation for consistency.
BitFullCalendarView lacks documentation while BitFullCalendarEventLayout and BitFullCalendarMode have comprehensive XML doc comments. Adding documentation would improve consistency across the public enum API and help developers understand which views are supported in different modes.
📝 Suggested documentation
+/// <summary> +/// Calendar view types available in Event mode. +/// Note: Timeline mode supports only Day, Week, and Month views. +/// </summary> public enum BitFullCalendarView { + /// <summary>Single day view with hourly time grid.</summary> Day, + /// <summary>Seven-day week view with hourly time grid.</summary> Week, + /// <summary>Month grid view showing all days and weeks of the month.</summary> Month, + /// <summary>Full year view with all months.</summary> Year, + /// <summary>Chronological agenda/list view groupable by date or color.</summary> Agenda }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarView.cs` around lines 3 - 10, Add XML documentation comments to the BitFullCalendarView enum and all its members (Day, Week, Month, Year, Agenda) to match the documentation style and completeness of BitFullCalendarEventLayout and BitFullCalendarMode. Include a summary comment for the enum itself explaining its purpose as the supported calendar view types, and add brief documentation for each enum member describing what each view represents or when it should be used.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razor (1)
43-45: ⚡ Quick winUse a semantic button for day selection.
The current clickable
<span>is not keyboard-friendly. Converting it to a<button>improves accessibility with minimal change.Proposed change
- <span class="bit-bfc-mini-calendar-day `@cls`" `@onclick`="() => SelectDate(cell.Date)"> - `@cell.Day` - </span> + <button type="button" + class="bit-bfc-mini-calendar-day `@cls`" + `@onclick`="() => SelectDate(cell.Date)" + aria-pressed="@(isSelected.ToString().ToLowerInvariant())"> + `@cell.Day` + </button>🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razor` around lines 43 - 45, Replace the non-semantic `<span>` element used for day selection in the BitFcMiniCalendar component with a `<button>` element to improve accessibility and keyboard navigation. The span element with the class "bit-bfc-mini-calendar-day" and the `@onclick` handler for SelectDate should be converted to a button while preserving the class binding, the onclick handler that calls SelectDate(cell.Date), and the displayed content `@cell.Day`.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razor (1)
40-44: 🏗️ Heavy liftMake resize handles keyboard-accessible.
The resize affordances are pointer-only, so keyboard users cannot perform duration edits from this component. Please add a keyboard path (focusable handle + key bindings) with accessible semantics.
Also applies to: 68-72
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razor` around lines 40 - 44, The resize handles in BitFcEventBlock are only accessible via pointer events, preventing keyboard users from resizing events. Make the resize handles keyboard-accessible by adding tabindex="0" to make them focusable, adding keyboard event handlers (like `@onkeydown`) alongside the existing `@onpointerdown` handlers to respond to arrow keys or Enter, and including appropriate ARIA attributes such as role="button" and aria-label to describe the handle's purpose. Apply these changes to both the top resize handle (with _topHandleId) and the bottom resize handle referenced in the "Also applies to" comment at lines 68-72.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razor (1)
80-86: ⚡ Quick winMake timeline slot cells keyboard-operable.
These clickable
<div>slots currently require a pointer. Add focusability + keyboard activation to support keyboard users for slot-based add interactions.Also applies to: 107-113
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razor` around lines 80 - 86, The `<div>` element with class "bit-bfc-tl-cell" is only operable via mouse click. To make it keyboard-accessible, add the tabindex="0" attribute to the div to make it focusable, then add an `@onkeydown` event handler that detects Enter or Space key presses and calls the same OnSlotClickAsync(rowKey, day) method that the `@onclick` handler uses. Apply the same changes to all similar timeline slot cell elements throughout the component (also at lines 107-113).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razor.cs`:
- Around line 6-7: The BitFcCalendarToast component stores
CancellationTokenSource objects in the _removalTokens list but never removes
them after they are no longer needed, only cleaning them up at component
disposal. To prevent unbounded list growth on long-lived pages, remove each
CancellationTokenSource from the _removalTokens list after its associated toast
timer completes or the toast is manually dismissed. Locate where new
CancellationTokenSource instances are added to _removalTokens around line 16 and
the disposal logic at line 39, then add cleanup logic that removes the token
from the list immediately after the timeout or dismissal occurs rather than
waiting for component disposal.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.scss`:
- Line 3: Remove the .scss file extension from the import statement on line 3
where "functions.scss" is being imported, changing it to just "functions" to
comply with the scss/load-partial-extension rule. Additionally, locate the
keyframe definitions around lines 200 and 1106 in the BitFullCalendar.scss file
and rename them to follow the keyframes-name-pattern convention, which typically
requires lowercase names with hyphens rather than camelCase or other formats.
In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.ts`:
- Around line 104-141: The onPointerMove callback and endResize function
currently process events from any pointer instead of just the pointer that
initiated the resize operation. Add a check in the onPointerMove function to
verify that the incoming event's pointerId matches the activePointerId before
updating latestY. Similarly, in the endResize function, verify that the
triggering pointer's pointerId matches activePointerId before executing the
resize end logic. This ensures that multi-pointer input on touch or pen devices
only responds to movement and events from the pointer that started the resize
operation. Apply the same gate logic to the second occurrence of these event
handlers mentioned in the comment (lines 179-215).
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razor.cs`:
- Around line 71-74: The OnFocusOut method unconditionally closes the panel by
setting _isOpen to false, which causes it to close prematurely when users
interact with child controls. Instead of always closing, modify the OnFocusOut
method to check whether the focus is moving to a child element within the picker
component or genuinely leaving it entirely. You can inspect the relatedTarget
property from the FocusEventArgs to determine if focus is moving to an internal
child element (in which case keep the picker open) or if it's moving outside the
component (in which case close it). Alternatively, implement a small delay
before closing to allow child click handlers to execute, then check if focus has
returned to the picker before proceeding with the close operation.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razor`:
- Around line 3-8: The BitFcDraggableEvent component's interactive div element
is currently not keyboard-accessible. To fix this, add keyboard event handling
to the div by adding an `@onkeydown` event handler that triggers the same OnClick
behavior when the Enter or Space key is pressed, and add a tabindex="0"
attribute to make the div focusable for keyboard users. This ensures that
keyboard users can interact with the draggable event the same way mouse users
can through the click handler.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razor`:
- Around line 54-63: The Agenda Group By options use non-semantic div elements
with `@onclick` handlers which are not keyboard-accessible or focusable. Replace
both div elements (the one with
SetAgendaModeGroupBy(BitFullCalendarAgendaGroupBy.Date) and the one with
SetAgendaModeGroupBy(BitFullCalendarAgendaGroupBy.Color)) with button elements
instead. Keep all the same class bindings, style bindings, and click handlers
intact, but change the element type from div to button to make them properly
focusable and keyboard-operable.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorOption.cs`:
- Around line 14-43: The Defaults property in the BitFullCalendarColorOption
class exposes a list of mutable objects that can be modified by consumers,
causing global side effects across all calendar instances. Make the
BitFullCalendarColorOption class immutable by converting it to a record type or
by changing the Id, Title, and Value properties to use init-only accessors
instead of set accessors. This ensures that the default color instances returned
from the Defaults property cannot be mutated after initialization.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorScheme.cs`:
- Around line 20-29: The snapshot of options in the BitFullCalendarColorScheme
constructor is shallow, copying only list references not the individual
BitFullCalendarColorOption objects themselves. This means if any
BitFullCalendarColorOption (especially its Id property) is mutated after
construction, the _byId dictionary will become out of sync with the Options
list. To fix this, perform a deep copy of each BitFullCalendarColorOption object
when populating the Options collection, and build the _byId dictionary from this
deep-copied Options collection to ensure the lookup and options list remain
consistent even if the original objects are mutated later.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cs`:
- Around line 8-9: The BitFullCalendarEvent model allows invalid event ranges
where EndDate could be less than StartDate, resulting in a negative duration
calculation at line 27 that propagates to the HandleDrop method in
BitFullCalendarState and causes invalid state updates. Add validation in the
BitFullCalendarEvent class (either in property setters for StartDate and EndDate
or in a constructor) to enforce the invariant that EndDate must be greater than
or equal to StartDate, rejecting any attempt to create or update an event with
an inverted date range at the model boundary before the invalid data reaches the
drag/drop logic.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarHelpers.cs`:
- Around line 510-515: The Where clause filtering events in the day range check
is inconsistent with how GroupEventsByDayRange handles exclusive midnight
boundaries. Currently using ev.EndDate.Date treats midnight as inclusive,
causing events ending at 00:00 to appear on the next day. Modify the EndDate
logic in this Where clause (around the line with ev.EndDate.Date) to match the
exclusive-midnight handling already implemented in GroupEventsByDayRange at line
375, ensuring events ending at midnight do not appear as carry-over in
subsequent month cells.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarState.cs`:
- Around line 178-186: The SyncEvents method short-circuits when EventsMatch
returns true on lines 180-181 without calling ApplyFilters on line 184, causing
filtered events to become stale when individual event objects are mutated
in-place (such as Color or attendees changes). Remove the early return condition
or restructure the method to ensure ApplyFilters and NotifyStateChanged are
always executed, even when the event list structure matches. This same issue
also exists in the other similar code block around lines 216-227.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razor`:
- Line 47: The search input element in BitFcAgendaEvents.razor lacks an
accessible label for screen readers, and the event rows referenced at lines
62-63 appear to be clickable divs rather than semantic interactive elements. Add
an associated label element (using for attribute) or aria-label to the search
input to describe its purpose, and convert the event row divs to button elements
or add proper ARIA role, tabindex, and keyboard event handlers to make them
accessible to keyboard and screen reader users.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razor`:
- Around line 34-38: The div elements used for hourly time slots in
BitFcCalendarDayView.razor (such as the div with class "bit-bfc-hour-row
bit-bfc-droppable" and `@onclick` handler "OnHourClickAsync") lack keyboard
accessibility, preventing keyboard-only users from creating events. Convert
these div elements to semantic button elements or add appropriate ARIA
attributes (role="button", tabindex, and `@onkeydown` handlers) to enable keyboard
interaction. Apply this fix to all similar time-slot divs including those around
the mentioned lines, ensuring both mouse clicks and keyboard events (Enter/Space
keys) trigger the OnHourClickAsync method.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razor`:
- Around line 35-37: The current filtering logic in the Where clause for
dayEvents uses date equality checks (e.StartDate.Date == d.Date ||
e.EndDate.Date == d.Date) which fails to correctly identify overlapping events,
particularly for events spanning multiple days or with exclusive end times.
Replace this equality-based filtering with proper interval overlap logic that
checks if the event overlaps with the current day using the condition:
event.StartDate is before the day's end AND event.EndDate is after the day's
start. This ensures all events that have any overlap with the day column are
included in dayEvents for the GroupEvents operation.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcCalendarMonthView.razor`:
- Around line 19-22: Add a `@key` directive to the BitFcDayCell component in the
foreach loop that iterates over cells to prevent Blazor from reusing component
instances by position when the month data changes. Use a unique identifier from
the cell object (such as the cell's date or a unique ID property) as the key
value to ensure each day cell maintains its own state and prevents stale UI
state like open dialogs from appearing in the wrong date cell.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcDayCell.razor`:
- Around line 8-12: The BitFcDayCell component's interactive div element is
currently only accessible via mouse clicks. To make it keyboard-accessible, add
tabindex="0" and role="button" attributes to the div element containing the
bit-bfc-month-cell class, then add an `@onkeydown` event handler that calls a new
OnCellKeyDown method. In the BitFcDayCell.razor.cs code-behind file, implement
the OnCellKeyDown handler that checks if the pressed key is Enter or Space, and
if so, awaits the OnCellClick() method to perform the same action as the click
handler.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razor`:
- Around line 108-121: The div elements with classes bit-bfc-tl-cell and
bit-bfc-tl-cell-half are currently non-focusable and only respond to mouse
events (onclick, ondrop, ondragenter), preventing keyboard-only users from
interacting with them. Make these elements keyboard-accessible by either
converting them to button elements with appropriate aria-labels, or keeping them
as divs but adding tabindex="0" to make them focusable and adding keyboard event
handlers (such as `@onkeydown`) that trigger the same OnSlotClickAsync and event
handler methods when Enter or Space keys are pressed.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razor`:
- Around line 31-38: The code is performing an expensive linear search through
all events for every cell in the year view, creating an O(cells × events)
performance bottleneck. Before the foreach loop that iterates over cells,
pre-compute a dictionary or lookup structure that maps dates to their
corresponding events from the allEvents collection. Then inside the foreach loop
in BitFcCalendarYearView.razor, replace the Where query with a simple dictionary
lookup using cell.Date.Date as the key to retrieve the dayEvents, eliminating
the per-cell scanning of all events.
- Around line 40-42: The year-day cell container (the div with class
bit-bfc-year-day) is using a clickable div element which is not
keyboard-accessible by default. To fix this in the BitFcCalendarYearView
component, replace the div with a button element (or add keyboard event handlers
like `@onkeydown` for Enter/Space keys along with tabindex="0" and appropriate
ARIA attributes if a button is not suitable). This will ensure that users can
open the ShowEventsForDay event list using keyboard navigation, making the
component fully accessible.
In `@src/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scss`:
- Line 7: The import statement for BitFullCalendar includes the `.scss` file
extension, which violates the stylelint scss/load-partial-extension rule. Remove
the `.scss` extension from the import path in the statement `@import
"../Components/FullCalendar/BitFullCalendar.scss";` so that it imports the
partial without the extension, allowing Stylelint to properly validate the
import and preventing pipeline check failures.
---
Minor comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razor`:
- Around line 4-7: The `@ondrop` event binding in the BitFcDroppableArea component
is missing the preventDefault directive that is already applied to `@ondragover`.
Add the :preventDefault="true" modifier to the `@ondrop` binding (similar to how
it is applied to `@ondragover`) to ensure the browser's default behavior is
prevented when items are dropped on the droppable area, avoiding accidental
navigation or unwanted content handling from external drops.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razor`:
- Around line 13-14: Add an explicit type="button" attribute to the button
element with class "bit-bfc-mode-tab" to prevent it from defaulting to type
submit and causing accidental form submissions when the calendar component is
placed within a form. This ensures the button only triggers the onclick handler
without submitting any parent form.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarOptions.cs`:
- Around line 16-17: The StartOfDayHour property in BitFullCalendarOptions class
lacks validation for the documented 0-16 range constraint, allowing any integer
value to be set. This causes runtime issues when the unconstrained value is
applied in BitFullCalendar.razor.cs. Add validation logic to the StartOfDayHour
property setter to enforce the 0-16 range by either clamping the value using
Math.Clamp or throwing an ArgumentException if an out-of-range value is
provided, ensuring the property contract matches its documentation.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarHelpers.cs`:
- Around line 83-87: The StartOfWeek method currently falls back to
DayOfWeek.Sunday when the culture parameter is null, instead of using the
current UI culture. Modify the startDay assignment in the StartOfWeek method to
use CultureInfo.CurrentUICulture.DateTimeFormat.FirstDayOfWeek as the fallback
instead of DayOfWeek.Sunday. This will make the method consistent with other
culture-aware methods and properly respect regional week start conventions when
no culture is explicitly provided.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razor.cs`:
- Around line 12-23: The Timer in the BitFcCalendarTimeline component is
configured with an initial due time of one minute, which causes the first
refresh to occur one minute after initialization rather than at the next minute
boundary. This misalignment can leave the "current time" marker behind by up to
60 seconds. Calculate the time remaining until the next minute boundary by
finding the current time's seconds and milliseconds, then subtracting from one
minute, and use this calculated TimeSpan as the dueTime parameter in the Timer
constructor instead of TimeSpan.FromMinutes(1), keeping TimeSpan.FromMinutes(1)
as the period for subsequent ticks. This ensures UpdatePosition is called at
clock minute transitions rather than arbitrary intervals.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razor.cs`:
- Around line 115-121: The OnAfterRenderAsync method calls
BitFcTimelineScrollInterop.TryScrollToTargetAsync on every render even when the
selected month is not the current month, resulting in unnecessary JavaScript
interop calls since there is no "today" target to scroll to in those cases. Add
a guard condition before calling
BitFcTimelineScrollInterop.TryScrollToTargetAsync that checks whether
State.SelectedDate (year and month) matches DateTime.Today (year and month), so
the interop only executes when the selected month is the current month. Keep the
existing _scrollSignature caching logic to prevent duplicate calls within the
same month.
---
Nitpick comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarView.cs`:
- Around line 3-10: Add XML documentation comments to the BitFullCalendarView
enum and all its members (Day, Week, Month, Year, Agenda) to match the
documentation style and completeness of BitFullCalendarEventLayout and
BitFullCalendarMode. Include a summary comment for the enum itself explaining
its purpose as the supported calendar view types, and add brief documentation
for each enum member describing what each view represents or when it should be
used.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razor`:
- Around line 40-44: The resize handles in BitFcEventBlock are only accessible
via pointer events, preventing keyboard users from resizing events. Make the
resize handles keyboard-accessible by adding tabindex="0" to make them
focusable, adding keyboard event handlers (like `@onkeydown`) alongside the
existing `@onpointerdown` handlers to respond to arrow keys or Enter, and
including appropriate ARIA attributes such as role="button" and aria-label to
describe the handle's purpose. Apply these changes to both the top resize handle
(with _topHandleId) and the bottom resize handle referenced in the "Also applies
to" comment at lines 68-72.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razor`:
- Around line 43-45: Replace the non-semantic `<span>` element used for day
selection in the BitFcMiniCalendar component with a `<button>` element to
improve accessibility and keyboard navigation. The span element with the class
"bit-bfc-mini-calendar-day" and the `@onclick` handler for SelectDate should be
converted to a button while preserving the class binding, the onclick handler
that calls SelectDate(cell.Date), and the displayed content `@cell.Day`.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razor`:
- Around line 80-86: The `<div>` element with class "bit-bfc-tl-cell" is only
operable via mouse click. To make it keyboard-accessible, add the tabindex="0"
attribute to the div to make it focusable, then add an `@onkeydown` event handler
that detects Enter or Space key presses and calls the same
OnSlotClickAsync(rowKey, day) method that the `@onclick` handler uses. Apply the
same changes to all similar timeline slot cell elements throughout the component
(also at lines 107-113).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 41c6cbda-5cbb-4b9d-844e-f448795bf9ba
📒 Files selected for processing (100)
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarBody.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarBody.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.scsssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcAddEditEventDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcAddEditEventDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventDetailsDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventDetailsDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarAgendaGroupBy.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarBadgeVariant.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarEventLayout.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarMode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarView.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcDateNavigator.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcDateNavigator.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcFilterEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcFilterEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcTodayButton.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcTodayButton.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcViewTabs.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcViewTabs.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarAttendee.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarCell.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarChangeEventArgs.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorOption.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorScheme.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarDateChangeEventArgs.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarOptions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarResource.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarTexts.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcAgendaScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcTimeGridScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcTimelineScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarChangeNotifier.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarHelpers.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarState.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcDayViewMultiDayEventsRow.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcDayViewMultiDayEventsRow.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcRenderGroupedEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcRenderGroupedEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcTimeColumn.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcTimeColumn.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcCalendarMonthView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcCalendarMonthView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcDayCell.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcDayCell.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcEventBullet.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcEventBullet.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcMonthEventBadge.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcMonthEventBadge.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineLayout.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineLayout.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scsssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razor.cssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/ComponentsSection.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/MainLayout.razor.NavItems.cs
|
@coderabbitai re-review |
|
✅ Action performedFull review finished. |
There was a problem hiding this comment.
Actionable comments posted: 16
🧹 Nitpick comments (3)
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razor.cs (1)
15-16: ⚡ Quick winAvoid redundant drag-over state writes.
ondragoverfires continuously; setting_isOver = trueeach time can cause unnecessary re-renders.Suggested fix
- private void OnDragOver() => _isOver = true; - private void OnDragLeave() => _isOver = false; + private void OnDragOver() + { + if (_isOver) return; + _isOver = true; + } + + private void OnDragLeave() + { + if (_isOver is false) return; + _isOver = false; + }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razor.cs` around lines 15 - 16, The OnDragOver method continuously sets _isOver to true every time the ondragover event fires, causing unnecessary re-renders even when the value is already true. Add a guard condition in the OnDragOver method to check if _isOver is already true before assigning the value, so that a re-render is only triggered when the state actually transitions from false to true.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarChangeNotifier.cs (1)
68-82: ⚡ Quick win
CloneEventdocumentation overstates deep-copy behavior.
Datais copied by reference on Line 81, so this is not a full deep snapshot. Either deep-cloneData(if supported) or adjust the XML docs to avoid a misleading contract.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarChangeNotifier.cs` around lines 68 - 82, The CloneEvent method's XML documentation claims to create a deep snapshot, but the Data property on Line 81 is copied by reference rather than being deep-cloned, making the documentation misleading. Either implement deep-cloning logic for the Data property assignment in the CloneEvent method to match the documented behavior, or revise the XML documentation summary to accurately describe that this method creates a shallow copy of the event with reference-type properties like Data and Attendees being copied by reference rather than cloned.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razor (1)
4-10: ⚡ Quick winExpose dropdown expanded state for accessibility.
The toggle button currently doesn’t announce menu state/ownership. Adding
aria-expanded/aria-controlsimproves keyboard and screen-reader flow.💡 Suggested fix
- <button class="bit-bfc-btn bit-bfc-btn-icon bit-bfc-btn-sm" `@onclick`="() => _open = !_open" title="`@Texts.SettingsButtonTitle`"> + <button type="button" + class="bit-bfc-btn bit-bfc-btn-icon bit-bfc-btn-sm" + `@onclick`="() => _open = !_open" + title="`@Texts.SettingsButtonTitle`" + aria-haspopup="menu" + aria-expanded="`@_open`" + aria-controls="bit-bfc-settings-menu"> @@ - <div class="bit-bfc-dropdown-menu"> + <div id="bit-bfc-settings-menu" class="bit-bfc-dropdown-menu" role="menu">🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razor` around lines 4 - 10, The button element in BitFcSettings.razor that toggles the dropdown menu is missing accessibility attributes. Add the aria-expanded attribute to the button and bind it to the _open variable to expose the expanded state to screen readers, add an id attribute to the div with class bit-bfc-dropdown-menu to uniquely identify it, and add the aria-controls attribute to the button to establish the relationship between the button and the dropdown menu it controls by referencing the dropdown menu's id.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.ts`:
- Around line 96-143: The event listeners for pointermove, pointerup, and
pointercancel are being registered after awaiting OnResizeStart, which allows a
fast pointer release to occur before the listeners are attached, causing the
endResize handler to be missed and leaving event listeners active. Move the
three addEventListener calls (for pointermove with onPointerMove, pointerup with
endResize, and pointercancel with endResize) to execute before the await of
OnResizeStart so that any pointer events are properly captured. Apply this same
ordering fix to the initResizeHorizontal function as well.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcAddEditEventDialog.razor`:
- Around line 76-78: The three input fields for attendee information
(_newFirstName, _newLastName, and _newId) lack explicit labels or aria-label
attributes, making them inaccessible to screen readers. Add aria-label
attributes to each of these input elements that describe the field's purpose
using the corresponding localized text from the Texts resource
(FirstNamePlaceholder, LastNamePlaceholder, and IdOptionalPlaceholder). This
ensures screen reader users can understand what information each field expects
without relying solely on visual placeholders.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razor`:
- Around line 14-18: The aria-label attributes on the navigation buttons (lines
14 and 18) in BitFcDateTimePicker.razor are hard-coded with English text,
preventing localization based on the selected culture. Add two new string
parameters named PreviousMonthAriaLabel and NextMonthAriaLabel to the
component's code-behind (BitFcDateTimePicker.razor.cs) with appropriate default
English values, then bind these parameters to the respective aria-label
attributes in the Razor markup by replacing the hard-coded strings with property
bindings.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razor`:
- Around line 12-23: The event row in BitFcEventListDialog.razor is currently
only mouse-clickable and inaccessible to keyboard users. The div with class
"bit-bfc-agenda-item" needs to be made keyboard-operable by adding a tabindex
attribute to make it focusable, and adding a keyboard event handler (such as
`@onkeydown`) that triggers the SelectEvent method when the user presses Enter or
Space keys. This ensures both mouse and keyboard users can select events from
the dialog.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razor`:
- Around line 8-20: The guard condition at the start of the BitFcModeTabs
component hides the entire mode tabs container when there are no resources,
which removes the Event mode switching UI entirely. Instead of conditionally
rendering the entire div based on resource count, you should keep the mode tabs
container always visible and conditionally filter or render only the
Timeline-specific mode from the _modes collection when resources are available.
This way the Event mode tab remains accessible for users to switch between modes
even when the resources list is empty.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razor.cs`:
- Around line 11-12: The SetStartOfDayHour method is being called with an
unclamped parsed value, which bypasses min/max validation that only exists on
the input element. After successfully parsing the value into the variable val
using int.TryParse, clamp val to the appropriate valid range (e.g., 0-23 for
hours) before passing it to State.SetStartOfDayHour to ensure the state
invariant is enforced at the handler level regardless of input element
constraints.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcViewTabs.razor`:
- Around line 9-10: The button element in BitFcViewTabs.razor does not have an
explicit type attribute, which causes it to default to type="submit" when inside
a form, potentially triggering unwanted form submissions. Add the type="button"
attribute to the button element that has the class "bit-bfc-view-tab" and the
onclick handler that calls State.SetView(view) to ensure it functions as a
regular button rather than a submit button.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarHelpers.cs`:
- Around line 201-210: The GetEventsForYear method in BitFullCalendarHelpers
treats EndDate.Date as inclusive in its overlap comparison, but this causes
inconsistency with the exclusive-end convention used elsewhere where midnight is
treated as the boundary. Fix the comparison logic in the where clause for
GetEventsForYear to treat EndDate as exclusive by changing the condition from
ev.EndDate.Date >= yearStart to ev.EndDate > yearStart. Apply this same
exclusive-end rule consistently across all other related date-overlap helper
methods mentioned in the comment (at lines 468-471, 578-588, 591-597, 599-609)
to ensure events ending at midnight do not incorrectly appear in the next
period.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razor`:
- Around line 43-47: The clickable div element in the BitFcCalendarWeekView
component that handles the `@onclick`="() => OnHourClickAsync(d, hour)" event is
not keyboard accessible. To fix this, add a role="button" attribute to indicate
this element is interactive, add tabindex="0" to make it focusable for keyboard
navigation, and add an `@onkeydown` event handler that triggers OnHourClickAsync
when the Enter or Space keys are pressed to allow keyboard-only users to create
events from the week grid view.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razor`:
- Around line 43-45: Replace the span element with role="button" in the
BitFcMiniCalendar component with a native button element for proper keyboard
semantics. Change the span that contains the SelectDate click handler and
OnDayKeyDown keyboard handler to a button element. Remove the role="button",
tabindex="0" attributes and the `@onkeydown` handler since native buttons
automatically handle keyboard interactions like Space and Enter. Keep the class
attribute with bit-bfc-mini-calendar-day and the `@onclick` handler bound to
SelectDate(cell.Date).
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcDayCell.razor`:
- Around line 47-49: The div element with class "bit-bfc-month-more" in
BitFcDayCell.razor is not keyboard-accessible because it only responds to click
events. Add an `@onkeydown` event handler to this div that calls a new
OnMoreKeyDown method, which should check if the pressed key is Enter, Space, or
Spacebar and set _showEventList to true when triggered. Additionally, add
tabindex="0" and role="button" attributes to the div to make it focusable and
semantically correct for keyboard users.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcMonthEventBadge.razor`:
- Around line 47-50: The time display in the MonthView badge incorrectly shows
Event.StartDate for all positions, including when Position is "last". For
multi-day events, the last segment should display Event.EndDate instead of
Event.StartDate to correctly represent the trailing day's time. Modify the
condition that checks showTime to conditionally use either Event.EndDate when
Position equals "last" or Event.StartDate otherwise, passing the appropriate
date value to the BitFullCalendarHelpers.FormatTime method.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razor`:
- Around line 16-19: The code filters out resources with empty IDs on line 17
when grouping events using `Where(id => !string.IsNullOrEmpty(id))`, but the
same filtering is not applied when rendering rows and drop targets around line
55 where raw `resource.Id` values are used directly. This inconsistency causes
resources with empty IDs to render but fail to retain dropped or created events
properly since the BitFullCalendarEvent.Resource contract treats empty IDs as
unassigned. Apply the same empty ID filtering logic when iterating through
resources for row and drop target rendering to ensure consistency between the
grouping logic and the rendering logic.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razor.cs`:
- Around line 78-83: In the `OnResizeStart` method in
BitFcTimelineEventBlock.razor.cs, instead of storing a direct reference to the
Event object in `_resizeBaseEvent`, capture an immutable copy or deep clone of
the Event object to preserve its pre-resize state. This ensures that when
`State.UpdateEvent(updated)` is called later and the original Event object is
mutated, the `_resizeBaseEvent` will still contain the original unmodified state
needed for building the accurate `OldEvent` property. Apply the same fix to the
corresponding resize end handler method that also uses `_resizeBaseEvent` to
construct `OldEvent`.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razor.cs`:
- Around line 119-124: The year and month comparison in the conditional check
within the method is using Gregorian calendar properties directly
(State.SelectedDate.Year and State.SelectedDate.Month), but the rendered
calendar may use a different calendar system based on the active culture.
Replace the direct Year and Month property comparisons with culture-aware date
comparison that respects the calendar system being used for rendering, ensuring
that the scroll-to-today functionality works correctly for non-Gregorian
calendar cultures.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razor`:
- Around line 44-46: The clickable div element with `@onclick` handler for
GoToMonth month navigation is not keyboard-accessible. Replace the div element
with a button element to make it keyboard-operable by default, which will allow
users to navigate using Tab and Enter keys. The button should maintain the same
click handler `@onclick`="() => GoToMonth(monthDate)" and display the monthName
content.
---
Nitpick comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razor.cs`:
- Around line 15-16: The OnDragOver method continuously sets _isOver to true
every time the ondragover event fires, causing unnecessary re-renders even when
the value is already true. Add a guard condition in the OnDragOver method to
check if _isOver is already true before assigning the value, so that a re-render
is only triggered when the state actually transitions from false to true.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razor`:
- Around line 4-10: The button element in BitFcSettings.razor that toggles the
dropdown menu is missing accessibility attributes. Add the aria-expanded
attribute to the button and bind it to the _open variable to expose the expanded
state to screen readers, add an id attribute to the div with class
bit-bfc-dropdown-menu to uniquely identify it, and add the aria-controls
attribute to the button to establish the relationship between the button and the
dropdown menu it controls by referencing the dropdown menu's id.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarChangeNotifier.cs`:
- Around line 68-82: The CloneEvent method's XML documentation claims to create
a deep snapshot, but the Data property on Line 81 is copied by reference rather
than being deep-cloned, making the documentation misleading. Either implement
deep-cloning logic for the Data property assignment in the CloneEvent method to
match the documented behavior, or revise the XML documentation summary to
accurately describe that this method creates a shallow copy of the event with
reference-type properties like Data and Attendees being copied by reference
rather than cloned.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 336fa9f8-c43a-4be3-81b7-7b5b95625510
📒 Files selected for processing (100)
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarBody.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarBody.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.scsssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcAddEditEventDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcAddEditEventDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventDetailsDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventDetailsDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarAgendaGroupBy.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarBadgeVariant.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarEventLayout.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarMode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarView.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcDateNavigator.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcDateNavigator.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcFilterEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcFilterEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcTodayButton.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcTodayButton.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcViewTabs.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcViewTabs.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarAttendee.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarCell.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarChangeEventArgs.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorOption.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorScheme.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarDateChangeEventArgs.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarOptions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarResource.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarTexts.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcAgendaScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcTimeGridScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcTimelineScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarChangeNotifier.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarHelpers.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarState.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcDayViewMultiDayEventsRow.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcDayViewMultiDayEventsRow.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcRenderGroupedEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcRenderGroupedEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcTimeColumn.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcTimeColumn.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcCalendarMonthView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcCalendarMonthView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcDayCell.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcDayCell.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcEventBullet.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcEventBullet.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcMonthEventBadge.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcMonthEventBadge.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineLayout.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineLayout.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scsssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razor.cssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/ComponentsSection.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/MainLayout.razor.NavItems.cs
|
@coderabbitai re-review |
|
✅ Action performedFull review finished. |
There was a problem hiding this comment.
Actionable comments posted: 10
♻️ Duplicate comments (1)
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razor.cs (1)
11-12:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winClamp parsed start-hour before updating state.
Line 11–12 still forwards raw parsed values; enforce the 0–16 bound in the handler so state cannot drift out of range.
Suggested fix
- if (int.TryParse(e.Value?.ToString(), out int val)) - State.SetStartOfDayHour(val); + if (int.TryParse(e.Value?.ToString(), out int val)) + State.SetStartOfDayHour(Math.Clamp(val, 0, 16));🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razor.cs` around lines 11 - 12, The handler for the start-hour input does not validate that the parsed value falls within the valid 0-16 range before forwarding it to State.SetStartOfDayHour. After successfully parsing the value with int.TryParse, clamp the parsed integer val to ensure it stays within bounds (minimum 0, maximum 16) before passing it to the SetStartOfDayHour method call.
🧹 Nitpick comments (2)
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.razor.cs (1)
199-210: 💤 Low valueOptions changes not detected when properties are modified in place.
ReferenceEqualscheck means if the consumer modifies properties on the existingOptionsinstance (e.g.,Options.Use24HourFormat = false) without assigning a new object, those changes won't be applied. Consider adding a version/hash check or documenting that a newOptionsinstance must be assigned for changes to take effect.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.razor.cs` around lines 199 - 210, The ApplyOptions method uses ReferenceEquals to compare Options with _appliedOptions, which only detects changes when a completely new Options object is assigned, not when individual properties are modified on the existing instance. To fix this, implement a version tracking mechanism or hash-based comparison that can detect property changes within the same Options object. You could add a version property to the Options class that increments when properties change, or compute a hash of the Options properties and compare that instead of just the reference. Store the computed hash or version in _appliedOptions alongside or in place of the Options reference, then check if the current hash/version differs from the stored one in the ApplyOptions method.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razor.cs (1)
100-107: Add State.IsDragging guard to OnDrop for consistency.While
HandleResourceDropAsyncproperly guards against null dragged events, theOnDropmethod should match the defensive pattern used in allOnDragEnterimplementations by checkingif (!State.IsDragging) return;early. This prevents unnecessary notifier calls and ensures consistent drag-state gating across event handlers.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razor.cs` around lines 100 - 107, Add a defensive guard clause at the beginning of the OnDrop method to check State.IsDragging, returning early if it is false. This ensures consistency with the defensive pattern used in OnDragEnter implementations and prevents unnecessary notifier calls when dragging is not actually in progress.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razor.cs`:
- Around line 21-32: The OnParametersSet method currently only reinitializes
_visibleMonthAnchor when the Value parameter changes, but does not account for
culture or calendar changes. To fix this, track the current culture or calendar
system similar to how _lastSyncedDate is tracked, and modify the OnParametersSet
method to reinitialize _visibleMonthAnchor not only when Value changes but also
when the culture or calendar system changes. This ensures that month anchoring
remains correct when switching between different calendar systems while
maintaining the same date value.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razor`:
- Around line 4-9: The button element in BitFcSettings component uses a
hardcoded ID "bit-bfc-settings-menu" in the aria-controls attribute, and the
menu div also uses the same hardcoded id. When multiple calendar instances exist
on the same page, this creates duplicate IDs which breaks accessibility by
causing assistive technology to point to the wrong menu. Generate a unique
identifier for each BitFcSettings component instance (typically using Guid in
the code-behind section) and replace both the aria-controls attribute on the
button and the id attribute on the menu div to use this generated unique ID
instead of the hardcoded string.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcTodayButton.razor`:
- Line 3: The button element in BitFcTodayButton.razor with the onclick handler
State.GoToToday and classes bit-bfc-btn bit-bfc-btn-sm is missing an explicit
type attribute. Add type="button" to the button element to ensure it never
accidentally submits a parent form when clicked.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarAttendee.cs`:
- Around line 15-17: The Initials property getter assumes FirstName and LastName
are non-null strings, which can cause null reference exceptions when these
properties are externally assigned null values. Add null checks before accessing
the Length property on FirstName and LastName in the Initials getter. Use the
null-coalescing operator or conditional checks to ensure that null values are
safely handled, treating them as empty strings when determining the initials.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarHelpers.cs`:
- Around line 213-218: The FormatTime method uses CultureInfo.InvariantCulture
for date formatting, which prevents localized time strings (particularly AM/PM
indicators) from respecting the user's UI culture settings. Replace
CultureInfo.InvariantCulture with CultureInfo.CurrentUICulture in both toString
calls within the FormatTime method to ensure time formatting respects the user's
locale. Additionally, apply the same fix to the similar code at lines 248-254
that handles the same formatting issue.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarState.cs`:
- Around line 48-52: The SetCulture method updates the Culture property and
calls UpdateUI() but fails to notify listeners about date-range changes. When
culture changes, the date range representation may change due to locale-specific
formatting, so consumers listening for range changes miss required updates. Add
a call to NotifyDateRangeChanged() after the UpdateUI() call in the SetCulture
method to ensure all listeners are properly notified of the date-range change.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razor.cs`:
- Line 3: The BitFcCalendarTimeline class has a Dispose() method defined on line
37 but does not implement the IDisposable interface on the class declaration on
line 3. Update the class declaration to implement IDisposable so that Blazor
will automatically call the Dispose() method when the component is destroyed,
ensuring the timer resource is properly cleaned up and doesn't leak.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razor.cs`:
- Around line 66-76: The catch block in the resize initialization section of
BitFcEventBlock only catches JSException, but other exceptions like
JSDisconnectedException, InvalidOperationException, and
OperationCanceledException can occur during Blazor teardown and disconnect
scenarios. Update the catch block that surrounds the JS.InvokeVoidAsync calls
for "BitBlazorUI.FullCalendar.initResize" (in the OnAfterRenderAsync method) to
catch all these exception types together, aligning the exception handling
pattern with the equivalent implementation in BitFcTimelineEventBlock.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razor`:
- Around line 40-47: The div element in the BitFcTimelineEventBlock component is
not keyboard-accessible because it lacks focus capability and keyboard event
handling. Make the event block keyboard-activatable by adding a tabindex
attribute to make the div focusable, adding an onkeydown event binding to the
div element, and implementing the corresponding OnKeyDown method that checks if
the pressed key is Enter, Space, or Spacebar before invoking the same OnClick
handler used for mouse clicks.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razor`:
- Around line 80-85: The timeline month slot cells in the BitFcTimelineMonthView
component (the div elements with classes bit-bfc-tl-cell bit-bfc-tl-cell-day at
lines 80-85 and 107-112) currently only respond to mouse interactions through
onclick handlers. To make these cells keyboard-operable, add keyboard event
handlers (`@onkeydown` or similar) to the div elements that trigger the same
OnSlotClickAsync method when the Enter or Space keys are pressed. This will
enable users to create events using keyboard navigation without requiring a
mouse, improving accessibility.
---
Duplicate comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razor.cs`:
- Around line 11-12: The handler for the start-hour input does not validate that
the parsed value falls within the valid 0-16 range before forwarding it to
State.SetStartOfDayHour. After successfully parsing the value with int.TryParse,
clamp the parsed integer val to ensure it stays within bounds (minimum 0,
maximum 16) before passing it to the SetStartOfDayHour method call.
---
Nitpick comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.razor.cs`:
- Around line 199-210: The ApplyOptions method uses ReferenceEquals to compare
Options with _appliedOptions, which only detects changes when a completely new
Options object is assigned, not when individual properties are modified on the
existing instance. To fix this, implement a version tracking mechanism or
hash-based comparison that can detect property changes within the same Options
object. You could add a version property to the Options class that increments
when properties change, or compute a hash of the Options properties and compare
that instead of just the reference. Store the computed hash or version in
_appliedOptions alongside or in place of the Options reference, then check if
the current hash/version differs from the stored one in the ApplyOptions method.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razor.cs`:
- Around line 100-107: Add a defensive guard clause at the beginning of the
OnDrop method to check State.IsDragging, returning early if it is false. This
ensures consistency with the defensive pattern used in OnDragEnter
implementations and prevents unnecessary notifier calls when dragging is not
actually in progress.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 5c0cef1e-f38f-4cd6-8f87-040157a9122a
📒 Files selected for processing (100)
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarBody.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarBody.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.scsssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcAddEditEventDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcAddEditEventDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventDetailsDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventDetailsDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarAgendaGroupBy.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarBadgeVariant.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarEventLayout.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarMode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarView.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcDateNavigator.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcDateNavigator.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcFilterEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcFilterEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcTodayButton.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcTodayButton.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcViewTabs.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcViewTabs.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarAttendee.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarCell.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarChangeEventArgs.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorOption.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorScheme.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarDateChangeEventArgs.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarOptions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarResource.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarTexts.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcAgendaScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcTimeGridScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcTimelineScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarChangeNotifier.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarHelpers.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarState.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcDayViewMultiDayEventsRow.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcDayViewMultiDayEventsRow.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcRenderGroupedEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcRenderGroupedEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcTimeColumn.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcTimeColumn.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcCalendarMonthView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcCalendarMonthView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcDayCell.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcDayCell.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcEventBullet.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcEventBullet.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcMonthEventBadge.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcMonthEventBadge.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineLayout.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineLayout.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scsssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razor.cssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/ComponentsSection.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/MainLayout.razor.NavItems.cs
|
@coderabbitai re-review |
|
✅ Action performedFull review finished. |
There was a problem hiding this comment.
Actionable comments posted: 6
♻️ Duplicate comments (6)
src/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scss (1)
7-7:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winRemove the
.scssextension to satisfy Stylelint.The static analysis tool flags this import as violating
scss/load-partial-extension. Other imports in this file omit the extension for consistency.Suggested fix
-@import "../Components/FullCalendar/BitFullCalendar.scss"; +@import "../Components/FullCalendar/BitFullCalendar";🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scss` at line 7, The import statement in the extra-components.scss file includes the .scss file extension on the BitFullCalendar.scss import, which violates the scss/load-partial-extension Stylelint rule. Remove the .scss extension from the import path so it matches the pattern used by other imports in the file, changing the import to reference just the module name without the extension.Source: Linters/SAST tools
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razor (1)
108-126:⚠️ Potential issue | 🟠 Major | ⚡ Quick winTimeline week slot cells lack keyboard accessibility.
Unlike
BitFcTimelineMonthView.razorwhich was updated withrole="button",tabindex="0", and@onkeydownhandlers, these week view cells remain mouse-only. Keyboard users cannot create events in this view.Add the same keyboard support pattern used in the month view:
Suggested fix for outer cell
<div class="bit-bfc-tl-cell @(isPreviewHour ? "bit-bfc-tl-drop-preview" : "")" style="left:@(leftPx)px;width:@(hourWidth)px;" + role="button" + tabindex="0" `@ondragenter`="() => OnDragEnter(rowKey, day, hour, 0)" `@ondragover`:preventDefault="true" `@ondrop`="() => OnDrop(rowKey, day, hour, 0)" - `@onclick`="() => OnSlotClickAsync(rowKey, day, hour, 0)"> + `@onclick`="() => OnSlotClickAsync(rowKey, day, hour, 0)" + `@onkeydown`="e => OnSlotKeyDownAsync(e, rowKey, day, hour, 0)">Also applies to lines 151-165 in UnassignedRowContent.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razor` around lines 108 - 126, The timeline week view cells in BitFcTimelineWeekView.razor are not keyboard accessible like they are in BitFcTimelineMonthView.razor. Add keyboard support to both the outer cell div with class "bit-bfc-tl-cell" and the inner cell-half div with class "bit-bfc-tl-cell-half" by adding three attributes to each: role="button" to provide semantic meaning, tabindex="0" to make them focusable, and `@onkeydown` event handler that calls the same OnSlotClickAsync method as the `@onclick` handler (with the same rowKey, day, hour, and minute parameters). Apply the same fix to both occurrences in the week view at the specified line ranges and also to the same cells in the UnassignedRowContent section at lines 151-165.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razor.cs (1)
3-3:⚠️ Potential issue | 🟠 Major | ⚡ Quick winImplement
IDisposableon the component type.Line 37 defines
Dispose(), but Line 3 does not implementIDisposable; Blazor lifecycle disposal won’t reliably invoke this cleanup, so the timer can outlive the component.Suggested fix
-public partial class BitFcCalendarTimeline +public partial class BitFcCalendarTimeline : IDisposableAlso applies to: 37-37
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razor.cs` at line 3, The BitFcCalendarTimeline class has a Dispose() method defined but does not implement the IDisposable interface. This prevents Blazor from reliably calling the cleanup method, allowing the timer to outlive the component. Add the IDisposable interface implementation to the BitFcCalendarTimeline class declaration so that the existing Dispose() method is properly recognized and invoked during component lifecycle cleanup.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.scss (1)
3-3:⚠️ Potential issue | 🟡 Minor | 💤 Low valueRemove
.scssextension from import path.The stylelint rule
scss/load-partial-extensionflags this. SCSS partials should be imported without the extension.-@import "../../../Bit.BlazorUI/Styles/functions.scss"; +@import "../../../Bit.BlazorUI/Styles/functions";🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.scss` at line 3, The import statement for the functions.scss partial includes the file extension, which violates the scss/load-partial-extension stylelint rule. Remove the .scss extension from the import path in the `@import` statement that references ../../../Bit.BlazorUI/Styles/functions.scss, so the partial is imported without its extension as per SCSS conventions.Source: Linters/SAST tools
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cs (1)
8-9:⚠️ Potential issue | 🟠 Major | ⚡ Quick winEnforce
EndDate >= StartDatein the model.Line 27 can return a negative duration today, and that value is consumed downstream when events are moved/resized. Reject inverted ranges at this boundary so invalid events never enter state logic.
Suggested fix
public class BitFullCalendarEvent { + private DateTime _startDate; + private DateTime _endDate; + public string Id { get; set; } = string.Empty; public string Title { get; set; } = string.Empty; public string Description { get; set; } = string.Empty; - public DateTime StartDate { get; set; } - public DateTime EndDate { get; set; } + public DateTime StartDate + { + get => _startDate; + set + { + _startDate = value; + EnsureValidRange(); + } + } + public DateTime EndDate + { + get => _endDate; + set + { + _endDate = value; + EnsureValidRange(); + } + } @@ public TimeSpan Duration => EndDate - StartDate; @@ public object? Data { get; set; } + + private void EnsureValidRange() + { + if (_startDate != default && _endDate != default && _endDate < _startDate) + throw new ArgumentOutOfRangeException(nameof(EndDate), "EndDate must be greater than or equal to StartDate."); + } }Also applies to: 27-27
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cs` around lines 8 - 9, The BitFullCalendarEvent model's StartDate and EndDate properties do not validate that EndDate is greater than or equal to StartDate, which allows negative durations to be calculated and propagated to downstream logic. Add validation logic to the EndDate property setter to ensure it is never set to a value less than the current StartDate value, and similarly validate the StartDate property setter to ensure it is never set to a value greater than the current EndDate value. This will prevent invalid inverted date ranges from being created at the model boundary and protect the duration calculations and event manipulation logic downstream.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarState.cs (1)
181-186:⚠️ Potential issue | 🟠 Major | ⚡ Quick win
SyncEventsstill skips filter recomputation for in-place mutations.Line 182 returns early when references match, so
_filteredEventscan stay stale after mutating event properties (for exampleColororAttendees) on shared instances.Suggested fix
public void SyncEvents(List<BitFullCalendarEvent> events) { if (EventsMatch(events)) - return; + { + ApplyFilters(); + return; + } _allEvents = [.. events]; ApplyFilters(); NotifyStateChanged(); }Also applies to: 217-227
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarState.cs` around lines 181 - 186, The SyncEvents method currently returns early when EventsMatch(events) is true, but this optimization causes _filteredEvents to become stale when individual event properties are mutated in-place (such as Color or Attendees changes on shared event instances). Remove the early return condition and the EventsMatch check so that ApplyFilters() and NotifyStateChanged() are always executed, ensuring that any in-place mutations to event properties trigger filter recomputation. Apply the same fix to the similar code block mentioned in the comment (lines 217-227) to ensure consistent behavior across all event synchronization paths.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razor`:
- Line 4: The button element in BitFcSettings.razor that toggles the _open state
is missing an explicit type attribute, which causes it to default to
type="submit" and can unintentionally submit a parent form. Add type="button" to
the button element with the `@onclick`="() => _open = !_open" handler to prevent
form submission behavior and explicitly declare that this is a regular button
control.
- Around line 12-37: The three toggle setting rows use non-semantic `<div>`
elements with `@onclick` handlers instead of proper button controls, making them
inaccessible via keyboard and screen readers. Replace each `<div
class="bit-bfc-dropdown-item">` element (the ones containing SetBadgeVariant,
ToggleTimeFormat, and ToggleEventLayout handlers) with `<button type="button">`
elements, preserving the existing `@onclick` handlers and all internal content
including the span labels and toggle markup. This ensures keyboard navigation
and proper semantic accessibility.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razor.cs`:
- Around line 97-104: The OnDrop method is calling HandleResourceDropAsync
unconditionally, but it should only do so when a drag operation is actually
active. Before calling the Notifier.HandleResourceDropAsync method in OnDrop,
add a guard condition to check if an active drag state exists (such as verifying
that _dragResourceId is not null before the reset). If no drag is active, the
method should return early without processing the drop logic, making it
consistent with the week view implementation.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineLayout.razor`:
- Around line 25-30: The condition checking `!hasResources` at line 25 prevents
the unassigned timeline row from rendering when resources are empty. Modify the
logic to show the empty state message only if both resources are empty AND there
are no unassigned rows to display. When resources are empty but
`HasUnassignedRow` is true or `UnassignedRowContent` exists, render the
unassigned timeline row instead of the no-resources message. Apply the same fix
to the related section at lines 60-72 to ensure consistent behavior throughout
the BitFcTimelineLayout component.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razor.cs`:
- Around line 111-119: The OnDrop method in BitFcTimelineMonthView.razor.cs is
missing a drag-state precondition check at the start of the method. Add a guard
clause at the beginning of the OnDrop method that checks if drag mode is active
(validate that _dragResourceId and _dragDay are not null) and returns early if
drag is not active, matching the behavior implemented in the timeline week view.
This check should occur before clearing the drag state variables and calling
HandleResourceDropAsync.
In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razor`:
- Line 5: The Description attribute in the BitFullCalendarDemo.razor file
contains inconsistent casing that makes it appear unprofessional and awkward for
users. Update the Description property value to properly capitalize component
names: change "fullcalendar" to "FullCalendar" and "bit BlazorUI" to "Bit
BlazorUI". Consider also improving the overall phrasing to be more polished and
user-facing, such as emphasizing that this is a powerful calendar component
within the Bit BlazorUI library rather than just stating it is a component of
it.
---
Duplicate comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.scss`:
- Line 3: The import statement for the functions.scss partial includes the file
extension, which violates the scss/load-partial-extension stylelint rule. Remove
the .scss extension from the import path in the `@import` statement that
references ../../../Bit.BlazorUI/Styles/functions.scss, so the partial is
imported without its extension as per SCSS conventions.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cs`:
- Around line 8-9: The BitFullCalendarEvent model's StartDate and EndDate
properties do not validate that EndDate is greater than or equal to StartDate,
which allows negative durations to be calculated and propagated to downstream
logic. Add validation logic to the EndDate property setter to ensure it is never
set to a value less than the current StartDate value, and similarly validate the
StartDate property setter to ensure it is never set to a value greater than the
current EndDate value. This will prevent invalid inverted date ranges from being
created at the model boundary and protect the duration calculations and event
manipulation logic downstream.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarState.cs`:
- Around line 181-186: The SyncEvents method currently returns early when
EventsMatch(events) is true, but this optimization causes _filteredEvents to
become stale when individual event properties are mutated in-place (such as
Color or Attendees changes on shared event instances). Remove the early return
condition and the EventsMatch check so that ApplyFilters() and
NotifyStateChanged() are always executed, ensuring that any in-place mutations
to event properties trigger filter recomputation. Apply the same fix to the
similar code block mentioned in the comment (lines 217-227) to ensure consistent
behavior across all event synchronization paths.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razor.cs`:
- Line 3: The BitFcCalendarTimeline class has a Dispose() method defined but
does not implement the IDisposable interface. This prevents Blazor from reliably
calling the cleanup method, allowing the timer to outlive the component. Add the
IDisposable interface implementation to the BitFcCalendarTimeline class
declaration so that the existing Dispose() method is properly recognized and
invoked during component lifecycle cleanup.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razor`:
- Around line 108-126: The timeline week view cells in
BitFcTimelineWeekView.razor are not keyboard accessible like they are in
BitFcTimelineMonthView.razor. Add keyboard support to both the outer cell div
with class "bit-bfc-tl-cell" and the inner cell-half div with class
"bit-bfc-tl-cell-half" by adding three attributes to each: role="button" to
provide semantic meaning, tabindex="0" to make them focusable, and `@onkeydown`
event handler that calls the same OnSlotClickAsync method as the `@onclick`
handler (with the same rowKey, day, hour, and minute parameters). Apply the same
fix to both occurrences in the week view at the specified line ranges and also
to the same cells in the UnassignedRowContent section at lines 151-165.
In `@src/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scss`:
- Line 7: The import statement in the extra-components.scss file includes the
.scss file extension on the BitFullCalendar.scss import, which violates the
scss/load-partial-extension Stylelint rule. Remove the .scss extension from the
import path so it matches the pattern used by other imports in the file,
changing the import to reference just the module name without the extension.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: e07c6d12-2eca-4898-a0d1-6974feaee4e1
📒 Files selected for processing (100)
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarBody.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarBody.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.scsssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcAddEditEventDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcAddEditEventDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventDetailsDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventDetailsDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarAgendaGroupBy.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarBadgeVariant.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarEventLayout.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarMode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarView.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcDateNavigator.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcDateNavigator.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcFilterEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcFilterEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcTodayButton.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcTodayButton.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcViewTabs.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcViewTabs.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarAttendee.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarCell.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarChangeEventArgs.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorOption.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorScheme.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarDateChangeEventArgs.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarOptions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarResource.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarTexts.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcAgendaScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcTimeGridScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcTimelineScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarChangeNotifier.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarHelpers.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarState.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcDayViewMultiDayEventsRow.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcDayViewMultiDayEventsRow.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcRenderGroupedEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcRenderGroupedEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcTimeColumn.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcTimeColumn.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcCalendarMonthView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcCalendarMonthView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcDayCell.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcDayCell.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcEventBullet.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcEventBullet.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcMonthEventBadge.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcMonthEventBadge.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineLayout.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineLayout.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scsssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razor.cssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/ComponentsSection.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/MainLayout.razor.NavItems.cs
There was a problem hiding this comment.
Actionable comments posted: 11
♻️ Duplicate comments (5)
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razor.cs (1)
10-10: 🎯 Functional Correctness | 🟠 MajorTrack the calendar implementation in the sync key, not just
CultureInfo.Name.This still misses culture changes that keep the same name but swap
State.Culture.Calendar, so the mini-calendar can keep the old month normalization even thoughStartOfDisplayMonth()now resolves through a different calendar.Suggested fix
- private string? _lastSyncedCultureName; + private string? _lastSyncedCultureKey; @@ - _lastSyncedCultureName = State.Culture.Name; + _lastSyncedCultureKey = $"{State.Culture.Name}|{State.Culture.Calendar.GetType().FullName}"; @@ - || !string.Equals(_lastSyncedCultureName, State.Culture.Name, StringComparison.Ordinal)) + || !string.Equals(_lastSyncedCultureKey, $"{State.Culture.Name}|{State.Culture.Calendar.GetType().FullName}", StringComparison.Ordinal)) { _lastSyncedSelectedDate = State.SelectedDate; - _lastSyncedCultureName = State.Culture.Name; + _lastSyncedCultureKey = $"{State.Culture.Name}|{State.Culture.Calendar.GetType().FullName}"; _displayMonth = StartOfDisplayMonth(State.SelectedDate); }Also applies to: 25-30
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razor.cs` at line 10, The mini-calendar sync key only tracks CultureInfo.Name, so it can miss changes where the culture name stays the same but State.Culture.Calendar changes and month normalization becomes stale. Update the sync tracking in BitFcMiniCalendar to include the calendar implementation alongside the culture name, and use that expanded key wherever _lastSyncedCultureName is compared or assigned so the sync logic reruns when the calendar type changes.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcMonthEventBadge.razor (1)
17-24: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winInclude dates in the badge’s accessible name.
The new
aria-labelstill omits the event dates, so multi-day/overnight badges can be announced as an ambiguous time range only. Include the start/end dates in the label as well.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcMonthEventBadge.razor` around lines 17 - 24, The accessible name built in BitFcMonthEventBadge.razor via badgeAriaLabel only includes the event title and times, so update that label to also include the start and end dates for Event.StartDate and Event.EndDate, using the existing BitFullCalendarHelpers formatting patterns and State.Culture/State.Use24HourFormat. Keep the aria-label on the badge element in sync so multi-day and overnight events are announced with both dates and times.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razor.cs (1)
3-3: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick winImplement
IDisposableon the component class.Line 3 defines a component with a
Dispose()method (Line 29) but noIDisposableimplementation, so Blazor won’t invoke that cleanup automatically andState.OnStateChangedcan remain subscribed.Suggested fix
-public partial class BitFcCalendarHeader +public partial class BitFcCalendarHeader : IDisposable#!/bin/bash # Verify class declaration and disposal pattern in this file. cat -n src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razor.cs | sed -n '1,40p' rg -n "class BitFcCalendarHeader|OnStateChanged \+=|Dispose\(" src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razor.csAlso applies to: 27-29
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razor.cs` at line 3, The component class BitFcCalendarHeader currently defines a Dispose() cleanup method but does not implement IDisposable, so Blazor will not automatically call it; update the class declaration to implement IDisposable and keep the existing Dispose logic so the State.OnStateChanged subscription is always removed. Verify the disposal pattern around BitFcCalendarHeader and its Dispose method remains intact, and ensure any related subscription setup in the component is matched by the IDisposable cleanup path.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cs (1)
8-9: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winReject inverted event ranges at the model boundary.
StartDateandEndDatestill allowEndDate < StartDate. That makesDurationnegative on Line 36, andsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarState.cs:443-454reuses that duration when rebuilding dropped events, so one invalid model instance can propagate broken dates. Validate the invariant in the setters (or a shared validator) instead of relying on downstream code.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cs` around lines 8 - 9, BitFullCalendarEvent currently allows an invalid range where EndDate is earlier than StartDate, which can produce a negative Duration and later break event rebuilding in BitFullCalendarState. Add validation at the model boundary by enforcing the StartDate/EndDate invariant in the BitFullCalendarEvent property setters or a shared validator, and reject or normalize any inverted range before the object can be used downstream.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarBody.razor.cs (1)
3-35: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick winImplement
IDisposableon the component type.
Dispose()unsubscribesState.OnStateChanged, but Blazor won't call it unless the component implementsIDisposable. That leaves the subscription alive after teardown and can keep invokingRefreshon a disposed component.Suggested fix
-public partial class BitFcCalendarBody +public partial class BitFcCalendarBody : IDisposable🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarBody.razor.cs` around lines 3 - 35, BitFcCalendarBody currently unsubscribes in Dispose() but never declares IDisposable, so Blazor won’t invoke teardown cleanup. Update the BitFcCalendarBody component type to implement IDisposable, keeping the existing Dispose() method so State.OnStateChanged is unsubscribed when the component is disposed. Ensure the change is applied on the BitFcCalendarBody partial class alongside OnInitialized, Refresh, and ComputeEvents.
🧹 Nitpick comments (2)
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarHelpers.cs (1)
470-473: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winExtract the exclusive-end normalization into one helper.
The midnight-exclusive adjustment is now copy-pasted in three overlap helpers. Centralizing it will keep future date-overlap fixes from drifting again.
♻️ Proposed refactor
+ private static DateTime InclusiveEndDate(BitFullCalendarEvent ev) + => (ev.EndDate > ev.StartDate ? ev.EndDate.AddTicks(-1) : ev.EndDate).Date; + ... - var evEnd = (ev.EndDate > ev.StartDate ? ev.EndDate.AddTicks(-1) : ev.EndDate).Date; + var evEnd = InclusiveEndDate(ev); ... - var e = (ev.EndDate > ev.StartDate ? ev.EndDate.AddTicks(-1) : ev.EndDate).Date; + var e = InclusiveEndDate(ev); ... - var e = (ev.EndDate > ev.StartDate ? ev.EndDate.AddTicks(-1) : ev.EndDate).Date; + var e = InclusiveEndDate(ev);Also applies to: 516-520, 588-590
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarHelpers.cs` around lines 470 - 473, The midnight-exclusive end-date normalization is duplicated across the overlap helpers, so extract that logic into a single shared helper in BitFullCalendarHelpers and use it wherever ev.EndDate is adjusted. Update the overlap checks that currently inline the AddTicks(-1) and Date handling so they all call the same helper, keeping IsSingleDay, GroupEventsByDayRange, and the other overlap methods consistent.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarState.cs (1)
33-33: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winEncapsulate drag state mutations.
DraggedEventis publicly settable, so any caller can bypassStartDrag/EndDragand skipNotifyStateChanged(). Making the setter private keeps drag state transitions consistent.Suggested patch
- public BitFullCalendarEvent? DraggedEvent { get; set; } + public BitFullCalendarEvent? DraggedEvent { get; private set; }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarState.cs` at line 33, The drag state in BitFullCalendarState is too exposed because DraggedEvent can be set directly, bypassing StartDrag and EndDrag and skipping NotifyStateChanged. Make the DraggedEvent setter private so only the state transition methods control it, and keep all drag mutations routed through StartDrag/EndDrag to preserve consistent notifications.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.ts`:
- Around line 307-312: Guard the storage helpers in BitFullCalendar against
DOMException by wrapping getLocalStorage and setLocalStorage in try/catch, since
localStorage.getItem/setItem can throw when storage is blocked or unavailable.
Update getLocalStorage to return null on failure and make setLocalStorage a
no-op on failure so the JS interop path degrades cleanly without breaking
preference initialization.
- Around line 207-213: Serialize resize sessions per event instead of per handle
by moving the active-resize guard in BitFullCalendar.ts from the element-local
pointer flag to a shared per-dotNetRef tracker, since
BitFcTimelineEventBlock.razor.cs wires both handles to the same dotNetRef.
Update the pointerdown/pointermove/pointerup flow in the resize logic so only
one resize can run at a time for a given event across both handles, and ensure
the shared tracking is cleared after resize end/cancel.
- Around line 130-159: The async resize lifecycle in FullCalendar can still
surface unhandled promise rejections because `endResize` is used directly as a
DOM listener and also replayed from the deferred `pointerdown` flow. Update the
listener entry points around `endResize`, the deferred replay path, and the
related resize handlers mentioned in the comment to use non-async wrappers that
call the async work via `void ...catch(...)`, while keeping the existing cleanup
and `OnResizeMove`/`OnResizeEnd` sequencing intact.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcAddEditEventDialog.razor.cs`:
- Around line 138-185: The Submit flow in BitFcAddEditEventDialog is re-entrant
and can be invoked twice before the dialog closes, causing duplicate add/edit
operations. Add an _isSubmitting guard inside Submit so repeated clicks/Enter
return early while a save is in progress, and make sure the flag is set before
the event/state update work and cleared afterward. Also wire the primary action
in this dialog to respect that flag so the save button is disabled during the
in-flight Submit path.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcViewTabs.razor`:
- Around line 3-13: The view switcher in BitFcViewTabs should expose the
selected state to assistive technologies. Update the container in the tabs
markup to behave like a tablist, and give each button in the `@foreach` over
_views a tab role plus an aria-selected state based on State.View == view, or
refactor to reuse an existing tabs component with the same semantics. Keep the
existing click behavior via State.SetView(view) and preserve the timeline
filtering logic.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarState.cs`:
- Around line 80-97: SetMode in BitFullCalendarState currently always calls
NotifyDateRangeChanged after updating Mode and possibly clamping View, which can
trigger OnDateChange even when the visible date range did not change. Update the
SetMode flow to compare the previously reported range against the new
Start/End/View state and only invoke NotifyDateRangeChanged when that range
actually differs, keeping the visible-range callback behavior aligned with the
BitFullCalendar.razor.cs contract.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razor`:
- Around line 34-42: The hour slot div in BitFcCalendarDayView.razor behaves
like a button, but the current OnHourKeyDownAsync key handler still allows Space
to scroll the page. Update the keyboard handler binding on the pseudo-button
element to use a prevent-default modifier so Space activates the slot without
page scrolling, while keeping the existing OnHourKeyDownAsync behavior intact.
- Around line 8-9: The “Happening now” list in BitFcCalendarDayView only uses
SingleDayEvents, so multi-day events are missed while still active. Update the
currentEvents selection logic in the day view to include any in-progress events
from the multi-day events source as well as single-day events, using the
existing DateTime.Now range check against StartDate and EndDate. Keep the change
localized to the currentEvents computation in BitFcCalendarDayView so the
sidebar shows all currently ongoing events.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcDayCell.razor`:
- Around line 8-15: The month day cell in BitFcDayCell is incorrectly exposed as
a full button-like container while it also hosts separate interactive controls
such as BitFcMonthEventBadge and the “more events” trigger, causing nested
interactive semantics. Update the DayCell markup and related click/keyboard
handlers so the outer cell is just a non-button container, and move the
add-event action to a dedicated control or overlay that is separately focusable
and clickable. Make the same accessibility/interaction adjustment in the other
affected sections of BitFcDayCell where the cell wrapper currently behaves like
a button.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razor.cs`:
- Around line 66-80: The resize initialization in OnAfterRenderAsync can
partially succeed, leaving one handle registered while _resizeInitialized
remains false, which causes duplicate listeners on later renders. Update
BitFcTimelineEventBlock.razor.cs so the start and end handle initialization in
BitBlazorUI.FullCalendar.initResizeHorizontal is tracked separately or marked as
initialized per handle, and only retry the missing side instead of
re-registering both when one call has already succeeded. Keep the existing
exception handling, but ensure partial success does not reattach listeners on an
already-initialized handle.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razor`:
- Around line 68-77: The year-day button content in BitFcCalendarYearView
currently includes an invalid block-level wrapper inside the button, so update
the button’s children to use valid button content only. In the year-day
rendering block that contains ShowEventsForDay and the bit-bfc-year-day-bullets
markup, replace the inner div with inline-compatible content or a span-based
wrapper so the button remains semantically valid and accessible.
---
Duplicate comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarBody.razor.cs`:
- Around line 3-35: BitFcCalendarBody currently unsubscribes in Dispose() but
never declares IDisposable, so Blazor won’t invoke teardown cleanup. Update the
BitFcCalendarBody component type to implement IDisposable, keeping the existing
Dispose() method so State.OnStateChanged is unsubscribed when the component is
disposed. Ensure the change is applied on the BitFcCalendarBody partial class
alongside OnInitialized, Refresh, and ComputeEvents.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razor.cs`:
- Line 3: The component class BitFcCalendarHeader currently defines a Dispose()
cleanup method but does not implement IDisposable, so Blazor will not
automatically call it; update the class declaration to implement IDisposable and
keep the existing Dispose logic so the State.OnStateChanged subscription is
always removed. Verify the disposal pattern around BitFcCalendarHeader and its
Dispose method remains intact, and ensure any related subscription setup in the
component is matched by the IDisposable cleanup path.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cs`:
- Around line 8-9: BitFullCalendarEvent currently allows an invalid range where
EndDate is earlier than StartDate, which can produce a negative Duration and
later break event rebuilding in BitFullCalendarState. Add validation at the
model boundary by enforcing the StartDate/EndDate invariant in the
BitFullCalendarEvent property setters or a shared validator, and reject or
normalize any inverted range before the object can be used downstream.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razor.cs`:
- Line 10: The mini-calendar sync key only tracks CultureInfo.Name, so it can
miss changes where the culture name stays the same but State.Culture.Calendar
changes and month normalization becomes stale. Update the sync tracking in
BitFcMiniCalendar to include the calendar implementation alongside the culture
name, and use that expanded key wherever _lastSyncedCultureName is compared or
assigned so the sync logic reruns when the calendar type changes.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcMonthEventBadge.razor`:
- Around line 17-24: The accessible name built in BitFcMonthEventBadge.razor via
badgeAriaLabel only includes the event title and times, so update that label to
also include the start and end dates for Event.StartDate and Event.EndDate,
using the existing BitFullCalendarHelpers formatting patterns and
State.Culture/State.Use24HourFormat. Keep the aria-label on the badge element in
sync so multi-day and overnight events are announced with both dates and times.
---
Nitpick comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarHelpers.cs`:
- Around line 470-473: The midnight-exclusive end-date normalization is
duplicated across the overlap helpers, so extract that logic into a single
shared helper in BitFullCalendarHelpers and use it wherever ev.EndDate is
adjusted. Update the overlap checks that currently inline the AddTicks(-1) and
Date handling so they all call the same helper, keeping IsSingleDay,
GroupEventsByDayRange, and the other overlap methods consistent.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarState.cs`:
- Line 33: The drag state in BitFullCalendarState is too exposed because
DraggedEvent can be set directly, bypassing StartDrag and EndDrag and skipping
NotifyStateChanged. Make the DraggedEvent setter private so only the state
transition methods control it, and keep all drag mutations routed through
StartDrag/EndDrag to preserve consistent notifications.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: a35d24ec-b6fc-48c2-b0db-a42976d0be7e
📒 Files selected for processing (100)
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarBody.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarBody.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.scsssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcAddEditEventDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcAddEditEventDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventDetailsDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventDetailsDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarAgendaGroupBy.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarBadgeVariant.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarEventLayout.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarMode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarView.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcDateNavigator.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcDateNavigator.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcFilterEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcFilterEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcTodayButton.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcTodayButton.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcViewTabs.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcViewTabs.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarAttendee.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarCell.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarChangeEventArgs.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorOption.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorScheme.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarDateChangeEventArgs.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarResource.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarSettings.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarTexts.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcAgendaScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcTimeGridScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcTimelineScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarChangeNotifier.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarHelpers.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarState.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcDayViewMultiDayEventsRow.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcDayViewMultiDayEventsRow.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcRenderGroupedEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcRenderGroupedEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcTimeColumn.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcTimeColumn.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcCalendarMonthView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcCalendarMonthView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcDayCell.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcDayCell.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcEventBullet.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcEventBullet.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcMonthEventBadge.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcMonthEventBadge.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineLayout.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineLayout.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scsssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razor.cssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/ComponentsSection.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/MainLayout.razor.NavItems.cs
|
@coderabbitai re-review |
|
✅ Action performedFull review finished. |
There was a problem hiding this comment.
Actionable comments posted: 15
♻️ Duplicate comments (4)
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razor.cs (1)
66-80: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick winTrack resize initialization per handle.
If Line 73 succeeds and Line 74 throws,
_resizeInitializedstaysfalse. The next render re-runs both registrations and can attach duplicate listeners to the side that already succeeded, which makes resize callbacks fire multiple times.Suggested fix
private DotNetObjectReference<BitFcTimelineEventBlock>? _dotNetRef; +private bool _startResizeInitialized; +private bool _endResizeInitialized; private bool _resizeInitialized; @@ try { _dotNetRef ??= DotNetObjectReference.Create(this); - await JS.InvokeVoidAsync("BitBlazorUI.FullCalendar.initResizeHorizontal", _dotNetRef, _startHandleId, "start"); - await JS.InvokeVoidAsync("BitBlazorUI.FullCalendar.initResizeHorizontal", _dotNetRef, _endHandleId, "end"); - _resizeInitialized = true; + if (!_startResizeInitialized) + { + await JS.InvokeVoidAsync("BitBlazorUI.FullCalendar.initResizeHorizontal", _dotNetRef, _startHandleId, "start"); + _startResizeInitialized = true; + } + + if (!_endResizeInitialized) + { + await JS.InvokeVoidAsync("BitBlazorUI.FullCalendar.initResizeHorizontal", _dotNetRef, _endHandleId, "end"); + _endResizeInitialized = true; + } + + _resizeInitialized = _startResizeInitialized && _endResizeInitialized; }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razor.cs` around lines 66 - 80, Track resize initialization separately for each handle in BitFcTimelineEventBlock.OnAfterRenderAsync instead of using a single _resizeInitialized flag for both registrations. If initResizeHorizontal succeeds for the start handle but fails for the end handle, remember the successful side so the next render only retries the missing handle and does not re-register the already-initialized one. Update the state management around _dotNetRef, _startHandleId, and _endHandleId to avoid duplicate listeners and repeated resize callbacks.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razor (1)
17-18: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick winSeparate the synthetic unassigned row from actual unassigned lanes.
BitFcTimelineLayout.razoralready filters rendered resource rows withstring.IsNullOrWhiteSpaceat Line 18, but this view still buildsresourceIdswithIsNullOrEmpty. More importantly,hasUnassignedbecomestruewhen there are no resources even ifgroupedhas no_unassignedKey, so Line 39 and Line 133 can throw on an empty calendar. Normalize the IDs here too, then trackhasUnassignedEventsandunassignedLaneCountseparately from the fallback UI row.Suggested fix
- var resourceIds = resources.Select(r => r.Id).Where(id => !string.IsNullOrEmpty(id)).ToList(); + var resourceIds = resources.Select(r => r.Id).Where(id => !string.IsNullOrWhiteSpace(id)).ToList(); @@ - var hasUnassigned = (grouped.TryGetValue(_unassignedKey, out var u) && u.Count > 0) || resourceIds.Count == 0; + var hasUnassignedEvents = grouped.TryGetValue(_unassignedKey, out var unassignedLanes) && unassignedLanes.Count > 0; + var hasUnassigned = hasUnassignedEvents || resourceIds.Count == 0; + var unassignedLaneCount = hasUnassignedEvents ? unassignedLanes.Count : 1; @@ - UnassignedRowHeight="RowHeight(hasUnassigned ? grouped[_unassignedKey].Count : 1)"> + UnassignedRowHeight="RowHeight(unassignedLaneCount)"> @@ - `@if` (hasUnassigned) + `@if` (hasUnassignedEvents) { - `@RenderLanes`(grouped[_unassignedKey]) + `@RenderLanes`(unassignedLanes) }Also applies to: 30-39, 131-133
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razor` around lines 17 - 18, The timeline day view is conflating a synthetic fallback row with real unassigned resource lanes, which can break empty-calendar rendering. Update BitFcTimelineDayView.razor to normalize resource IDs the same way as BitFcTimelineLayout.razor does (use the same whitespace filtering), and split the logic into separate flags/counts for actual unassigned events versus the fallback “no resources” row. Make sure the grouping and render checks around the hasUnassigned path and the unassigned lane rendering only run when grouped actually contains the unassigned key, so empty calendars do not attempt to access missing unassigned data.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarResource.cs (1)
14-14: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick winReject blank resource IDs.
Line 14 makes
Idrequired, butrequiredstill allows""/whitespace.BitFullCalendarState.HandleDropcollapses null and empty to the same unassigned state, so blank ids are still ambiguous with “no resource” and can misroute event/resource associations.Suggested fix
+ private string _id = null!; - public required string Id { get; set; } + public required string Id + { + get => _id; + set => _id = string.IsNullOrWhiteSpace(value) + ? throw new ArgumentException("Resource id cannot be empty.", nameof(value)) + : value.Trim(); + }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarResource.cs` at line 14, Reject blank resource IDs by validating BitFullCalendarResource.Id beyond the current required modifier. Add input validation in BitFullCalendarResource so empty or whitespace-only values are not accepted, and ensure any creation/mapping path using Id enforces a non-blank value. This should align with BitFullCalendarState.HandleDrop, which already treats null and empty as unassigned, so the fix should prevent blank Ids from reaching that flow and being misinterpreted as a valid resource reference.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razor (1)
23-23: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winDon't key the week badges by
ev.Id.Line 23 reintroduces the same duplicate/missing-ID hazard the code-behind just removed from
_eventRows. If two events in the same day column share an ID, Blazor can diff them as the same child.Suggested fix
- <BitFcMonthEventBadge `@key`="ev.Id" Event="ev" CellDate="d" Position="`@position`" OnSelected="ShowEventDetails" EventTemplate="EventTemplate" /> + <BitFcMonthEventBadge `@key`="ev" Event="ev" CellDate="d" Position="`@position`" OnSelected="ShowEventDetails" EventTemplate="EventTemplate" />🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razor` at line 23, The `BitFcWeekViewMultiDayEventsRow` rendering is still keying `BitFcMonthEventBadge` by `ev.Id`, which can cause duplicate/missing-child diffing when same-day events share an ID. Update the `@key` in this loop to use a per-instance stable key from the event row context (matching the safer `_eventRows` approach) so each badge remains uniquely identified even when `ev.Id` collides.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razor`:
- Around line 4-8: The toast list rendering in BitFcCalendarToast.razor should
key each rendered toast by its stable Id so Blazor does not reuse DOM nodes when
_toasts is mutated. Update the foreach that renders each toast div to add an
`@key` using toast.Id, keeping the existing role/class logic in the same
BitFcCalendarToast.razor markup.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.scss`:
- Around line 144-151: The button group separators in the FullCalendar styles
are using a physical right border, which breaks RTL alignment; update the
.bit-bfc-btn-group and .bit-bfc-btn:last-child rules to use a logical inline-end
border instead of border-right so the divider stays between buttons in both
directions. Keep the existing selector structure in BitFullCalendar.scss and
adjust the border removal for the last button to match the logical property.
- Around line 681-684: The timeline resize preview is hard-coded to the left in
the .bit-bfc-timeline-event-resizing.bit-bfc-resize-dir-start
.bit-bfc-resize-preview rule, so it appears on the wrong side in RTL. Update the
FullCalendar SCSS so the start-edge preview is positioned using direction-aware
styling in the timeline resize styles, keeping the preview aligned with the
actual start edge for both LTR and RTL. Use the existing
.bit-bfc-timeline-event-resizing, .bit-bfc-resize-dir-start, and
.bit-bfc-resize-preview selectors to locate and adjust the rule.
In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.ts`:
- Around line 156-158: The resize lock is being released too early in
`initResizeVertical`, allowing another resize to start before `OnResizeEnd`
finishes. Move the `activePointerId`/`activeKey` reset to after the awaited
`dotNetRef.invokeMethodAsync("OnResizeEnd")`, and apply the same change in
`initResizeHorizontal` so both resize paths keep the guard held until
finalization completes.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcAddEditEventDialog.razor`:
- Around line 24-31: The start/end field labels are only visual in
BitFcAddEditEventDialog and are not associated with the focusable picker trigger
rendered by BitFcDateTimePicker. Update the dialog so the picker button is
explicitly tied to `@Texts.StartDateTimeLabel` and `@Texts.EndDateTimeLabel`, using
the picker’s accessible labeling/trigger props or a generated id from the label
element, so assistive tech announces the field name along with the current
value.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razor.cs`:
- Around line 72-78: SelectDate in BitFcDateTimePicker is updating Value and
_lastSyncedDate but not re-anchoring the calendar when a muted overflow day from
a neighboring month is chosen. Update the SelectDate flow so it also sets
_visibleMonthAnchor to the month of the selected date before closing the picker,
ensuring OnParametersSet does not keep reopening on the old month after a
cross-month selection.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razor`:
- Around line 12-23: The event-row markup in BitFcEventListDialog should be kept
valid by removing block-level children from the button. Update the button
content inside the event list rendering to use span-level elements instead of
div wrappers, and preserve the existing layout/spacing through CSS classes or
styles rather than nested div structure. Use the SelectEvent,
BitFullCalendarHelpers.FormatTime, and ColorScheme.GetColorStyle sections as the
locations to update.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cs`:
- Line 5: The month layout currently relies on raw event ids, so blank or
duplicate values from BitFullCalendarEvent.Id can overwrite each other in
BitFullCalendarHelpers.CalculateMonthEventPositions and GetMonthCellEvents. Add
ingestion-time normalization in the event pipeline before layout state is built
so every event has a stable unique key, and reject or remap duplicate/missing
ids instead of allowing string.Empty to flow into the dictionary keys used for
month positioning.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarState.cs`:
- Line 12: BitFullCalendarState is using DateTime.Today for SelectedDate and
GoToToday, which can resolve to the server’s date instead of the user’s
browser-local date in Blazor Server. Update BitFullCalendarState to accept a
browser-local “today” value from the caller (for both the initial SelectedDate
and GoToToday), and replace the direct DateTime.Today usage in the
constructor/state initialization and today-navigation path with that
injected/local date source.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razor`:
- Around line 36-54: The lower half-slot in BitFcCalendarDayView.razor is only
wired for drag/drop, so clicks and keyboard activation on that area still bubble
to the parent hour row and call OnHourClickAsync(hour), creating :00 events.
Update the hour-cell handling around the hour row and the nested half-slot so
the 30-minute slot has its own click/keydown target and invokes the existing
hour creation flow with minute 30, while preventing the parent OnHourClickAsync
from firing for that interaction.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razor`:
- Around line 45-47: The day button in BitFcMiniCalendar.razor currently exposes
only the day number through the button content, which makes repeated dates
indistinguishable to assistive technologies. Update the button in the
mini-calendar day cell to include an aria-label with a culture-formatted full
date derived from the same cell.Date used by SelectDate, while keeping the
visible `@cell.Day` text unchanged. Use the existing day button markup in
BitFcMiniCalendar and apply the accessible name directly on that button element.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razor.cs`:
- Around line 39-42: The StartOfDisplayMonth method in BitFcMiniCalendar should
preserve the source era when normalizing the date, because using the era-less
ToDateTime overload can select the wrong era or fail for era-based calendars.
Update the DateTime construction to use the calendar era from cal.GetEra(date)
together with the existing cal.GetYear(date) and cal.GetMonth(date) values so
the month is rebuilt in the same era as the input date.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcRenderGroupedEvents.razor`:
- Around line 14-35: The current overlap calculation in
BitFcRenderGroupedEvents.razor uses all intersecting lanes to derive depth,
which overcounts staggered conflicts. Update the grouped-events width logic
around the leftConflicts/rightConflicts and depth/rank computation so it
measures the peak number of simultaneous overlaps within ev’s own time range,
not just whether a lane intersects at any point. Keep the existing grouping
structure, but replace the lane-count approach with a concurrency-based
calculation that still feeds depth and rank for rendering.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razor`:
- Around line 68-78: The year-day button in BitFcCalendarYearView currently
exposes only the day number, which is ambiguous across the month grid. Update
the button in the year-view day cell rendering to include a culture-aware
full-date aria-label based on the cell’s date, while keeping the existing click
behavior in ShowEventsForDay and the visible day number unchanged. Use the day
cell rendering logic around cell.Date, cell.Day, and dayEvents to generate the
accessible name for each button.
In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razor`:
- Around line 141-146: The FullCalendar bound example is mixing initial-only
defaults with two-way bound values, so the default attributes never take effect.
In BitFullCalendarDemo.razor, remove the DefaultView, DefaultMode, and
DefaultDate attributes from the same BitFullCalendar usage that binds View,
Mode, and Date, and keep the bound properties as the single source of truth for
this demo snippet.
---
Duplicate comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarResource.cs`:
- Line 14: Reject blank resource IDs by validating BitFullCalendarResource.Id
beyond the current required modifier. Add input validation in
BitFullCalendarResource so empty or whitespace-only values are not accepted, and
ensure any creation/mapping path using Id enforces a non-blank value. This
should align with BitFullCalendarState.HandleDrop, which already treats null and
empty as unassigned, so the fix should prevent blank Ids from reaching that flow
and being misinterpreted as a valid resource reference.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razor`:
- Line 23: The `BitFcWeekViewMultiDayEventsRow` rendering is still keying
`BitFcMonthEventBadge` by `ev.Id`, which can cause duplicate/missing-child
diffing when same-day events share an ID. Update the `@key` in this loop to use
a per-instance stable key from the event row context (matching the safer
`_eventRows` approach) so each badge remains uniquely identified even when
`ev.Id` collides.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razor`:
- Around line 17-18: The timeline day view is conflating a synthetic fallback
row with real unassigned resource lanes, which can break empty-calendar
rendering. Update BitFcTimelineDayView.razor to normalize resource IDs the same
way as BitFcTimelineLayout.razor does (use the same whitespace filtering), and
split the logic into separate flags/counts for actual unassigned events versus
the fallback “no resources” row. Make sure the grouping and render checks around
the hasUnassigned path and the unassigned lane rendering only run when grouped
actually contains the unassigned key, so empty calendars do not attempt to
access missing unassigned data.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razor.cs`:
- Around line 66-80: Track resize initialization separately for each handle in
BitFcTimelineEventBlock.OnAfterRenderAsync instead of using a single
_resizeInitialized flag for both registrations. If initResizeHorizontal succeeds
for the start handle but fails for the end handle, remember the successful side
so the next render only retries the missing handle and does not re-register the
already-initialized one. Update the state management around _dotNetRef,
_startHandleId, and _endHandleId to avoid duplicate listeners and repeated
resize callbacks.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: a7205db9-14c2-4b24-b796-88d4a8ba8156
📒 Files selected for processing (100)
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarBody.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarBody.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.scsssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcAddEditEventDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcAddEditEventDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventDetailsDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventDetailsDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarAgendaGroupBy.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarBadgeVariant.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarEventLayout.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarMode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarView.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcDateNavigator.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcDateNavigator.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcFilterEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcFilterEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcTodayButton.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcTodayButton.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcViewTabs.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcViewTabs.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarAttendee.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarCell.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarChangeEventArgs.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorOption.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorScheme.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarDateChangeEventArgs.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarResource.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarSettings.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarTexts.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcAgendaScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcTimeGridScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcTimelineScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarChangeNotifier.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarHelpers.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarState.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcDayViewMultiDayEventsRow.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcDayViewMultiDayEventsRow.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcRenderGroupedEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcRenderGroupedEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcTimeColumn.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcTimeColumn.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcCalendarMonthView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcCalendarMonthView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcDayCell.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcDayCell.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcEventBullet.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcEventBullet.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcMonthEventBadge.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcMonthEventBadge.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineLayout.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineLayout.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scsssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razor.cssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/ComponentsSection.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/MainLayout.razor.NavItems.cs
|
@coderabbitai re-review |
|
✅ Action performedFull review finished. |
There was a problem hiding this comment.
Actionable comments posted: 14
♻️ Duplicate comments (2)
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razor (1)
9-21: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winKeep the Event mode tab reachable when resources are empty.
The guard on Line 9 removes the entire switch, but the public contract here says only the Timeline tab should disappear when
Resourcesis empty. That also removes the built-in way back to Event mode ifModeis stillTimelineafter resources are cleared.💡 Suggested fix
-@if (State.Resources.Count > 0) -{ - <div class="bit-bfc-mode-tabs"> - `@foreach` (var mode in _modes) - { - <button class="bit-bfc-mode-tab @(State.Mode == mode ? "active" : "")" - type="button" - `@onclick`="() => State.SetMode(mode)"> - `@Texts.GetModeLabel`(mode) - </button> - } - </div> -} +<div class="bit-bfc-mode-tabs"> + `@foreach` (var mode in _modes) + { + if (mode is BitFullCalendarMode.Timeline && State.Resources.Count == 0) continue; + + <button class="bit-bfc-mode-tab @(State.Mode == mode ? "active" : "")" + type="button" + `@onclick`="() => State.SetMode(mode)"> + `@Texts.GetModeLabel`(mode) + </button> + } +</div>🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razor` around lines 9 - 21, The conditional rendering in BitFcModeTabs currently hides the entire mode switch when State.Resources is empty, which also removes the Event tab and breaks the ability to switch back from Timeline. Update the guard so only the Timeline mode is omitted when resources are empty, while the Event mode button remains visible and still uses State.SetMode and the existing _modes/State.Mode logic to render and activate the available tabs.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcRenderGroupedEvents.razor (1)
14-35: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winCompute event width from peak concurrency, not any intersecting lane.
This still overcounts staggered overlaps. If
evoverlaps one lane in its first half and a different lane in its second half, Lines 25-33 producedepth == 3even though only two events are ever concurrent, so the card renders too narrow. Basedepthon the maximum simultaneous overlaps insideev's own interval instead of counting every lane that intersects it at any point.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcRenderGroupedEvents.razor` around lines 14 - 35, The current width calculation in BitFcRenderGroupedEvents.razor overcounts staggered overlaps by counting every intersecting lane around ev. Update the grouped-events logic so depth is derived from the maximum number of events simultaneously active within ev’s own time range, rather than leftConflicts/rightConflicts in the grouping loop. Use the existing grouping context in BitFcRenderGroupedEvents and the ev overlap checks to compute peak concurrency, then keep rank based on the event’s actual position within that peak group.
🧹 Nitpick comments (2)
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razor.cs (1)
10-21: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winMarshal the add path through the renderer as well.
RemoveAfterDelayalready usesInvokeAsync, butShowmutates_toastsand callsStateHasChanged()directly. If this public method is reached from JS interop or any background continuation, the first toast add is the path that will throw. Please either guarantee dispatcher-only callers or wrap this path the same way.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razor.cs` around lines 10 - 21, The toast add path in Show is still touching component state off-dispatcher, unlike RemoveAfterDelay. Update BitFcCalendarToast.Show so adding to _toasts and calling StateHasChanged are marshaled through InvokeAsync (or otherwise ensure only renderer-thread callers), using the Show, RemoveAfterDelay, and BitFcCalendarToast symbols to keep the full toast lifecycle dispatcher-safe.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razor.cs (1)
15-19: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win
OnDragOveris still a hot rerender path.The
_isOverguard skips the extra state write, but Blazor still schedules a render after each@ondragovercallback. In a slot-dense calendar, that can make drag interactions heavier than necessary. Consider suppressing rerenders once the slot is already active, or move the hover-class toggle out of the Blazor event loop.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razor.cs` around lines 15 - 19, The OnDragOver path in BitFcDroppableArea is still causing unnecessary renders on every drag-over callback even when _isOver is already true. Update the hover handling so the component does not rerender once the droppable slot is already active, either by suppressing render work in the component’s render flow or by moving the hover-class state toggle out of the Blazor event loop while keeping the OnDragOver guard in place.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.razor.cs`:
- Around line 354-366: ApplySettings in BitFullCalendar should not skip updates
based on ReferenceEquals(Settings, _appliedSettings), because in-place changes
on the same BitFullCalendarSettings instance are currently ignored. Update the
sync logic to compare and apply the individual setting values from Settings
(such as Use24HourFormat, BadgeVariant, StartOfDayHour, AgendaModeGroupBy,
EventLayout, and ShowDayViewCalendar) whenever they change, and keep
_appliedSettings only as the last synced snapshot if needed.
In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.ts`:
- Around line 148-160: The resize guard in BitFullCalendar’s resize-finalization
flow is only cleared after OnResizeEnd completes, so if that call throws the
event stays blocked; update the finalization logic in the resize handler that
uses dotNetRef, activePointerId, and activeKey so the guard reset runs even when
OnResizeEnd fails, ideally by moving the cleanup into a guaranteed finally path
and keeping the same behavior in both affected resize blocks.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcAddEditEventDialog.razor`:
- Around line 24-31: The add/edit dialog’s BitFcDateTimePicker instances are
missing the calendar’s 12/24-hour setting, so they always use the picker default
instead of the current calendar format. Update the BitFcAddEditEventDialog.razor
markup to pass State.Use24HourFormat into both BitFcDateTimePicker components
alongside Culture, matching the other FullCalendar surfaces that already honor
the calendar time format.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventDetailsDialog.razor.cs`:
- Around line 33-45: Guard the BitFcEventDetailsDialog.Delete flow against
double invocation by following the existing _isSubmitting pattern used elsewhere
in the dialog. Update Delete() to set and check a submission flag before calling
State.RemoveEvent(Event.Id), keep the flag true until the notifier and OnClose
complete, and prevent the delete button from being clickable while the action is
in flight. Use the Delete() method and the dialog’s existing button markup/state
to locate the fix.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarAttendee.cs`:
- Line 9: The FullName composition in BitFullCalendarAttendee only trims the
final combined string, so whitespace inside FirstName or LastName can still
create doubled spaces. Update the FullName property to normalize each component
before concatenating them, using the BitFullCalendarAttendee fields FirstName
and LastName so attendee labels render cleanly even when either name contains
surrounding spaces.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cs`:
- Around line 10-15: The default color handling in BitFullCalendarEvent is
hard-coded to “blue”, which causes mismatches when the active palette does not
include that value. Update the Color property and the related normalization path
so an unset color means “use the current scheme fallback” instead of a literal
default, and ensure BitFullCalendarState.ApplyFilters, GetLabel, and
GetEditorOptions all resolve missing/unknown colors against the configured
palette consistently.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarTexts.cs`:
- Around line 47-49: The event-list text properties in BitFullCalendarTexts are
currently fixed English fragments, which prevents proper localization and word
order in other languages. Update EventListTitlePrefix, EventListCountSuffix, and
MoreEventsSuffix to expose full format templates with placeholders, and adjust
the FullCalendar rendering/formatting code that consumes these strings so it
passes the needed values through the templates instead of concatenating English
fragments.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarChangeNotifier.cs`:
- Around line 88-95: The attendee cloning in BitFullCalendarChangeNotifier
currently assumes source.Attendees is always populated, which can throw during
drag/edit notifications. Update the cloning logic in the event mapping path to
handle a null Attendees collection safely, returning an empty list or preserving
null consistently before projecting BitFullCalendarAttendee items. Use the
source.Attendees access inside the change notification flow to locate the fix.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarHelpers.cs`:
- Around line 756-760: The Capitalize helper is using invariant casing, which
can produce incorrect results for localized text. Update
BitFullCalendarHelpers.Capitalize to use culture-aware casing instead of
char.ToUpperInvariant, and pass through the relevant current/supplied
CultureInfo so the first character is capitalized consistently with the rest of
the formatting helpers. Keep the null/empty handling and the rest of the string
slicing behavior unchanged.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarState.cs`:
- Around line 44-50: The event ID normalization in BitFullCalendarState is
mutating caller-owned BitFullCalendarEvent instances, which breaks the component
boundary. Update Initialize, SyncEvents, and NormalizeEventIds so normalization
happens on component-local copies or a separate internal key, instead of
rewriting BitFullCalendarEvent.Id on shared objects. Keep the existing event
list API, but ensure BitFullCalendarState owns any normalized IDs used for
indexing/rendering without changing the parent model’s instances.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razor`:
- Around line 62-85: The agenda item markup in BitFcAgendaEvents.razor uses a
button element to wrap multiple divs, which makes the button content invalid.
Update the render in the agenda row so the child content inside the button uses
phrasing-content wrappers such as spans, or change the container to a non-button
element and preserve the existing ShowDetails(ev) interaction and
BitFullCalendarHelpers formatting logic.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razor.cs`:
- Around line 70-74: The hour slot keyboard handler in OnHourKeyDownAsync needs
to ignore repeated keydown events so a held Enter or Spacebar doesn’t trigger
multiple additions. Update the KeyboardEventArgs check in BitFcCalendarDayView
to include the same !e.Repeat guard used by BitFcMonthEventBadge before calling
OnHourClickAsync, so only the first keydown creates the draft event.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razor.cs`:
- Around line 53-57: Prevent repeated keydown events from triggering multiple
hour actions in OnHourKeyDownAsync. Update the BitFcCalendarWeekView.razor.cs
keyboard handler so it ignores auto-repeat keydown events before calling
OnHourClickAsync, using the KeyboardEventArgs repeat state (or equivalent guard)
to ensure Enter/Space only fire once per intentional key press.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcDayViewMultiDayEventsRow.razor`:
- Line 9: The event badge in BitFcDayViewMultiDayEventsRow should not be keyed
by ev.Id because duplicate IDs can cause Blazor to reuse the wrong instance.
Update the BitFcMonthEventBadge usage in this row to key by the event object
itself, matching the existing approach used by the week-row component, so
sibling badges remain uniquely identified even when IDs repeat.
---
Duplicate comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razor`:
- Around line 9-21: The conditional rendering in BitFcModeTabs currently hides
the entire mode switch when State.Resources is empty, which also removes the
Event tab and breaks the ability to switch back from Timeline. Update the guard
so only the Timeline mode is omitted when resources are empty, while the Event
mode button remains visible and still uses State.SetMode and the existing
_modes/State.Mode logic to render and activate the available tabs.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcRenderGroupedEvents.razor`:
- Around line 14-35: The current width calculation in
BitFcRenderGroupedEvents.razor overcounts staggered overlaps by counting every
intersecting lane around ev. Update the grouped-events logic so depth is derived
from the maximum number of events simultaneously active within ev’s own time
range, rather than leftConflicts/rightConflicts in the grouping loop. Use the
existing grouping context in BitFcRenderGroupedEvents and the ev overlap checks
to compute peak concurrency, then keep rank based on the event’s actual position
within that peak group.
---
Nitpick comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razor.cs`:
- Around line 10-21: The toast add path in Show is still touching component
state off-dispatcher, unlike RemoveAfterDelay. Update BitFcCalendarToast.Show so
adding to _toasts and calling StateHasChanged are marshaled through InvokeAsync
(or otherwise ensure only renderer-thread callers), using the Show,
RemoveAfterDelay, and BitFcCalendarToast symbols to keep the full toast
lifecycle dispatcher-safe.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razor.cs`:
- Around line 15-19: The OnDragOver path in BitFcDroppableArea is still causing
unnecessary renders on every drag-over callback even when _isOver is already
true. Update the hover handling so the component does not rerender once the
droppable slot is already active, either by suppressing render work in the
component’s render flow or by moving the hover-class state toggle out of the
Blazor event loop while keeping the OnDragOver guard in place.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 786e9f97-910d-450f-be81-76def1fe5314
📒 Files selected for processing (100)
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarBody.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarBody.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.scsssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcAddEditEventDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcAddEditEventDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventDetailsDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventDetailsDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarAgendaGroupBy.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarBadgeVariant.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarEventLayout.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarMode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarView.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcDateNavigator.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcDateNavigator.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcFilterEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcFilterEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcTodayButton.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcTodayButton.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcViewTabs.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcViewTabs.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarAttendee.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarCell.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarChangeEventArgs.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorOption.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorScheme.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarDateChangeEventArgs.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarResource.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarSettings.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarTexts.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcAgendaScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcTimeGridScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcTimelineScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarChangeNotifier.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarHelpers.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarState.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcDayViewMultiDayEventsRow.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcDayViewMultiDayEventsRow.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcRenderGroupedEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcRenderGroupedEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcTimeColumn.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcTimeColumn.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcCalendarMonthView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcCalendarMonthView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcDayCell.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcDayCell.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcEventBullet.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcEventBullet.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcMonthEventBadge.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcMonthEventBadge.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineLayout.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineLayout.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scsssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razor.cssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/ComponentsSection.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/MainLayout.razor.NavItems.cs
|
@coderabbitai re-review |
|
✅ Action performedFull review finished. |
|
Action performedFull review triggered. |
There was a problem hiding this comment.
Actionable comments posted: 13
♻️ Duplicate comments (5)
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razor (1)
30-39: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick winDon't index
grouped[_unassignedKey]for the synthetic empty row.When there are no valid resources yet,
hasUnassignedbecomestruefromresourceIds.Count == 0, butgroupedstill has no_unassignedKeyentry until an actual unassigned event exists. Line 39 and Line 133 will then throw on the first empty render.🐛 Suggested fix
- var hasUnassigned = (grouped.TryGetValue(_unassignedKey, out var u) && u.Count > 0) || resourceIds.Count == 0; + var hasUnassignedEvents = grouped.TryGetValue(_unassignedKey, out var unassignedLanes) && unassignedLanes.Count > 0; + var hasUnassigned = hasUnassignedEvents || resourceIds.Count == 0; + var unassignedLaneCount = hasUnassignedEvents ? unassignedLanes.Count : 1; @@ - UnassignedRowHeight="RowHeight(hasUnassigned ? grouped[_unassignedKey].Count : 1)"> + UnassignedRowHeight="RowHeight(unassignedLaneCount)"> @@ - `@if` (hasUnassigned) + `@if` (hasUnassignedEvents) { - `@RenderLanes`(grouped[_unassignedKey]) + `@RenderLanes`(unassignedLanes) }Also applies to: 131-133
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razor` around lines 30 - 39, The unassigned-row height logic in BitFcTimelineDayView is indexing grouped[_unassignedKey] even when hasUnassigned is true only because resourceIds.Count is 0, which can throw before any unassigned bucket exists. Update the UnassignedRowHeight expression, and the matching height calculation at the other referenced spot, to safely handle the synthetic empty row by using the existing unassigned count only when the _unassignedKey entry is present, otherwise fall back to the empty-row height. Keep the fix localized to the hasUnassigned/grouped/_unassignedKey logic in this view.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cs (1)
8-9:⚠️ Potential issue | 🟠 MajorReject inverted event ranges at the model boundary.
Duration,IsSingleDay, and the layout/drop helpers all assumeEndDate >= StartDate, but the model still accepts inverted ranges. Validate the range on assignment or ingest so invalid events never enter calendar state.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cs` around lines 8 - 9, The BitFullCalendarEvent model still allows inverted date ranges, even though Duration, IsSingleDay, and the layout/drop helpers assume EndDate is never before StartDate. Add range validation at the model boundary in BitFullCalendarEvent so invalid events are rejected when StartDate/EndDate are assigned or when the event is created/ingested, using the model’s date properties as the enforcement point.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razor (1)
40-53: 🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy liftHonor the calendar's time format in this picker.
These selects still hardcode a 24-hour, invariant-digit model. Together with
GetDisplayText()inBitFcDateTimePicker.razor.cs, the add/edit flow will keep showingHH:mmeven afterBitFcSettingsswitches the calendar to 12-hour time.Suggested direction
// BitFcDateTimePicker.razor.cs +[Parameter] public bool Use24HourFormat { get; set; } = true;Then render the trigger text and time inputs from that flag, and pass
Use24HourFormat="State.Use24HourFormat"fromBitFcAddEditEventDialog.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razor` around lines 40 - 53, Honor the calendar time-format setting in BitFcDateTimePicker by replacing the hardcoded 24-hour selects and HH:mm display path with logic driven by the existing use-24-hour flag from BitFcSettings. Update the picker markup and the GetDisplayText() flow in BitFcDateTimePicker.razor.cs to render 12-hour or 24-hour values accordingly, and make BitFcAddEditEventDialog pass Use24HourFormat="State.Use24HourFormat" so the add/edit flow stays consistent with the calendar’s configured format.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razor.cs (1)
20-28: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick winHandle agenda scroll interop failures before they escape render.
This render-path await can still throw during prerender/disconnect/teardown and bring down the component instead of leaving the nonce in place for a later retry.
Suggested patch
protected override async Task OnAfterRenderAsync(bool firstRender) { var nonce = State.AgendaScrollToTodayNonce; if (nonce == _lastAgendaScrollNonce) return; - var scrolled = await BitFcAgendaScrollInterop.TryScrollToDateAsync(JS, _scrollContainerId, DateTime.Today); - if (scrolled) - _lastAgendaScrollNonce = nonce; + try + { + var scrolled = await BitFcAgendaScrollInterop.TryScrollToDateAsync(JS, _scrollContainerId, DateTime.Today); + if (scrolled) + _lastAgendaScrollNonce = nonce; + } + catch (Exception ex) when (ex is JSException or JSDisconnectedException or InvalidOperationException or OperationCanceledException) + { + // Retry on a later render once JS becomes available again. + } }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razor.cs` around lines 20 - 28, The agenda scroll render path in BitFcAgendaEvents.OnAfterRenderAsync can throw during prerender, disconnect, or teardown and prevent a later retry. Wrap the BitFcAgendaScrollInterop.TryScrollToDateAsync call in failure handling so interop exceptions are caught and do not escape the render cycle, and only update _lastAgendaScrollNonce when scrolling succeeds so the nonce remains available for a subsequent attempt.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razor.cs (1)
97-107: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick winGuard week-view scroll interop in the render path.
OnAfterRenderAsyncstill lets JS interop exceptions escape. A transient disconnect/teardown here can fail the render instead of retrying on the next pass.Suggested patch
protected override async Task OnAfterRenderAsync(bool firstRender) { var sig = BuildTimeGridScrollSignature(); if (sig == _timeGridScrollSignature) return; - if (await BitFcTimeGridScrollInterop.TryScrollToStartOfDayAsync( - JS, - _timeGridScrollElementId, - State.StartOfDayHour)) - _timeGridScrollSignature = sig; + try + { + if (await BitFcTimeGridScrollInterop.TryScrollToStartOfDayAsync( + JS, + _timeGridScrollElementId, + State.StartOfDayHour)) + _timeGridScrollSignature = sig; + } + catch (Exception ex) when (ex is JSException or JSDisconnectedException or InvalidOperationException or OperationCanceledException) + { + // Retry on a later render once JS becomes available again. + } }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razor.cs` around lines 97 - 107, The week-view render hook in BitFcCalendarWeekView.OnAfterRenderAsync can still throw from BitFcTimeGridScrollInterop.TryScrollToStartOfDayAsync, which may break the render on transient JS disconnects or teardown. Update OnAfterRenderAsync to guard the interop call with exception handling and only advance _timeGridScrollSignature after a successful scroll, so the render path can safely retry on the next pass.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razor.cs`:
- Around line 10-14: `BitFcCalendarToast.Show` allocates toast IDs with
`_nextId++`, which is not safe when `Show` is called concurrently off the
renderer thread. Update the ID generation in `Show` to use an atomic operation
so each `ToastItem.Id` is unique even under concurrent calls, and keep
`RemoveAfterDelay` unchanged since it relies on the `Id` assigned here.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.razor.cs`:
- Around line 281-296: The parameter update path is emitting multiple
intermediate OnDateChange callbacks because OnParametersSet() can trigger
several BitFullCalendarState setters in one pass and HandleDateRangeChanged()
forwards each OnDateRangeChanged notification immediately. Update the
BitFullCalendar.razor.cs flow so date-range changes caused by State.SetCulture,
State.SetMode/SetView, and State.SetSelectedDate are coalesced and only the
final resolved range is raised to consumers after ApplyBoundState() finishes.
Use the existing HandleDateRangeChanged and the state setters in
BitFullCalendarState as the main integration points.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.scss`:
- Around line 1819-1825: The toast severity accent in the bit-bfc-toast success
and error styles uses a physical left border, which breaks in RTL layouts.
Update the border definition in the bit-bfc-toast selectors to use a logical
leading-side border instead so the accent follows direction automatically. Keep
the change scoped to the existing success/error rules in BitFullCalendar.scss.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventDetailsDialog.razor.cs`:
- Around line 34-52: The Delete flow in BitFcEventDetailsDialog’s Delete method
leaves _isDeleting stuck true if Notifier.NotifyAsync or OnClose.InvokeAsync
throws, which blocks retries after the event has already been removed. Update
the Delete method to wrap the awaited notification/close sequence in try/finally
and reset _isDeleting in the finally block, keeping the existing
double-invocation guard while ensuring the dialog can recover on failure.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razor`:
- Around line 3-12: The BitFcDraggableEvent component currently wraps free-form
ChildContent inside a native button, which can produce invalid nested
interactive markup and interfere with click/drag behavior. Update the component
to use a non-button host element in BitFcDraggableEvent.razor while preserving
the existing drag/click handlers and styling, or alternatively tighten the
ChildContent contract so only phrasing content is allowed; make the change
around the draggable button markup and its OnDragStart, OnDragEnd, and OnClick
wiring.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorScheme.cs`:
- Around line 18-29: `BitFullCalendarColorScheme` currently builds `Options`
from the raw source list while `_byId` is built from trimmed, de-duplicated IDs,
so the UI can still show blank/duplicate entries that the resolver ignores.
Update the constructor to derive both `Options` and `_byId` from the same
canonicalized sequence (trim IDs, skip blanks, keep first unique ID) so `Find`
and `GetSortOrder` stay aligned with what `BitFcFilterEvents` and the editor
options expose.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarResource.cs`:
- Line 14: The BitFullCalendarResource.Id property only enforces initialization,
not valid runtime values, so update the resource model to reject null or blank
ids when instances are created or assigned. Add validation in
BitFullCalendarResource (or its creation path) so Id cannot be null, empty, or
whitespace, and ensure any grouping helpers that consume Id continue to assume a
non-empty key.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarHelpers.cs`:
- Around line 25-39: RangeText and FormatCultureDate are still hard-coding
English date ordering instead of using culture-specific patterns. Update
BitFullCalendarHelpers so the Month/Agenda header and the culture-formatted date
both rely on CultureInfo.DateTimeFormat patterns (or equivalent culture-aware
formatting) rather than manual $"{monthName} {year}" and "Mon d, yyyy"
interpolation, and keep the logic localized within RangeText and
FormatCultureDate.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razor.cs`:
- Around line 56-74: The add-event flow in BitFcCalendarDayView currently drops
minute information for click and keyboard interactions, so half-hour slots
cannot create or prefill a :30 draft. Update the hour click/keydown path by
threading minute through OnHourClickAsync and OnHourKeyDownAsync, then store and
pass the selected minute alongside _addStartHour in the dialog state. Also wire
the dedicated :30 slot handlers in BitFcCalendarDayView.razor to use the same
flow as the drop path so CreateDraftEventForTimeSlot receives both hour and
minute consistently.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcRenderGroupedEvents.razor`:
- Around line 60-62: The rendered event subtree in BitFcRenderGroupedEvents is
missing a stable key, so BitFcEventBlock instances can be reused for a different
ev during regrouping/reordering and carry stale state. Add a stable `@key` to the
event wrapper or BitFcEventBlock using a unique event identifier such as ev.Id,
keeping the key tied to the same ev instance across renders.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razor.cs`:
- Around line 111-135: `OnResizeMove` in `BitFcTimelineEventBlock` is using the
wrong units for the resize delta passed from the JS interop contract. Adjust the
method to treat the incoming value consistently with what `BitFullCalendar.ts`
sends, and remove the extra pixels-to-minutes conversion if the value is already
in minutes. Make sure the preview and committed range calculations in
`OnResizeMove` use the same unit end-to-end, and keep the dead-zone handling
aligned with that unit.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razor`:
- Around line 7-17: The YearView date calculations are not era-aware, so
`BitFcCalendarYearView.razor` can render the wrong range or fail in non-standard
calendars. Update the logic around `cal.GetMonthsInYear`, `cal.GetDaysInMonth`,
and `cal.ToDateTime` to first capture `cal.GetEra(State.SelectedDate)` and pass
that era explicitly into each calendar call, keeping the existing
`State.SelectedDate`, `culturalYear`, and `yearStartDate`/`yearEndDate`
calculations consistent for era-based calendars.
---
Duplicate comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razor`:
- Around line 40-53: Honor the calendar time-format setting in
BitFcDateTimePicker by replacing the hardcoded 24-hour selects and HH:mm display
path with logic driven by the existing use-24-hour flag from BitFcSettings.
Update the picker markup and the GetDisplayText() flow in
BitFcDateTimePicker.razor.cs to render 12-hour or 24-hour values accordingly,
and make BitFcAddEditEventDialog pass Use24HourFormat="State.Use24HourFormat" so
the add/edit flow stays consistent with the calendar’s configured format.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cs`:
- Around line 8-9: The BitFullCalendarEvent model still allows inverted date
ranges, even though Duration, IsSingleDay, and the layout/drop helpers assume
EndDate is never before StartDate. Add range validation at the model boundary in
BitFullCalendarEvent so invalid events are rejected when StartDate/EndDate are
assigned or when the event is created/ingested, using the model’s date
properties as the enforcement point.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razor.cs`:
- Around line 20-28: The agenda scroll render path in
BitFcAgendaEvents.OnAfterRenderAsync can throw during prerender, disconnect, or
teardown and prevent a later retry. Wrap the
BitFcAgendaScrollInterop.TryScrollToDateAsync call in failure handling so
interop exceptions are caught and do not escape the render cycle, and only
update _lastAgendaScrollNonce when scrolling succeeds so the nonce remains
available for a subsequent attempt.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razor.cs`:
- Around line 97-107: The week-view render hook in
BitFcCalendarWeekView.OnAfterRenderAsync can still throw from
BitFcTimeGridScrollInterop.TryScrollToStartOfDayAsync, which may break the
render on transient JS disconnects or teardown. Update OnAfterRenderAsync to
guard the interop call with exception handling and only advance
_timeGridScrollSignature after a successful scroll, so the render path can
safely retry on the next pass.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razor`:
- Around line 30-39: The unassigned-row height logic in BitFcTimelineDayView is
indexing grouped[_unassignedKey] even when hasUnassigned is true only because
resourceIds.Count is 0, which can throw before any unassigned bucket exists.
Update the UnassignedRowHeight expression, and the matching height calculation
at the other referenced spot, to safely handle the synthetic empty row by using
the existing unassigned count only when the _unassignedKey entry is present,
otherwise fall back to the empty-row height. Keep the fix localized to the
hasUnassigned/grouped/_unassignedKey logic in this view.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 285154e1-1349-436b-b5a3-0d1e8aa79e10
📒 Files selected for processing (100)
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarBody.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarBody.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.scsssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcAddEditEventDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcAddEditEventDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventDetailsDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventDetailsDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarAgendaGroupBy.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarBadgeVariant.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarEventLayout.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarMode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarView.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcDateNavigator.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcDateNavigator.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcFilterEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcFilterEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcTodayButton.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcTodayButton.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcViewTabs.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcViewTabs.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarAttendee.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarCell.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarChangeEventArgs.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorOption.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorScheme.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarDateChangeEventArgs.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarResource.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarSettings.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarTexts.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcAgendaScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcTimeGridScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcTimelineScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarChangeNotifier.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarHelpers.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarState.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcDayViewMultiDayEventsRow.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcDayViewMultiDayEventsRow.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcRenderGroupedEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcRenderGroupedEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcTimeColumn.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcTimeColumn.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcCalendarMonthView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcCalendarMonthView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcDayCell.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcDayCell.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcEventBullet.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcEventBullet.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcMonthEventBadge.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcMonthEventBadge.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineLayout.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineLayout.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scsssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razor.cssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/ComponentsSection.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/MainLayout.razor.NavItems.cs
|
@coderabbitai re-review |
|
✅ Action performedFull review finished. |
There was a problem hiding this comment.
Actionable comments posted: 8
♻️ Duplicate comments (4)
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.scss (1)
3-3: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick winRemove the
.scsssuffix from this import.Line 3 still violates
scss/load-partial-extension, so stylelint will keep failing here.Suggested fix
-@import "../../../Bit.BlazorUI/Styles/functions.scss"; +@import "../../../Bit.BlazorUI/Styles/functions";🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.scss` at line 3, The FullCalendar SCSS import is using a file extension that violates the stylesheet lint rule. Update the import in BitFullCalendar.scss to use the partial-style path without the .scss suffix, keeping the reference to functions.scss otherwise unchanged so stylelint passes.Source: Linters/SAST tools
src/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scss (1)
7-7: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick winDrop the
.scssextension in the new bundle import.Line 7 still hits
scss/load-partial-extension, which keeps the stylesheet bundle lint-red.Suggested fix
-@import "../Components/FullCalendar/BitFullCalendar.scss"; +@import "../Components/FullCalendar/BitFullCalendar";🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scss` at line 7, The new bundle import in extra-components.scss still includes the .scss extension and triggers the stylesheet lint rule. Update the top-level import for BitFullCalendar to use the partial-style path without the extension, keeping the import in extra-components.scss aligned with the bundle conventions.Source: Linters/SAST tools
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razor (1)
30-39: 🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win
grouped[_unassignedKey]can throwKeyNotFoundExceptionon an empty calendar.When
resourceIds.Count == 0and there are no unassigned events,hasUnassignedistruebutgroupedhas no_unassignedKeyentry. Line 39 (and Line 133) then indexgrouped[_unassignedKey]directly, crashing the render. Separate the "needs a row" flag from the actual lanes.🐛 Proposed fix
- var hasUnassigned = (grouped.TryGetValue(_unassignedKey, out var u) && u.Count > 0) || resourceIds.Count == 0; + var hasUnassignedEvents = grouped.TryGetValue(_unassignedKey, out var unassignedLanes) && unassignedLanes.Count > 0; + var hasUnassigned = hasUnassignedEvents || resourceIds.Count == 0; @@ - UnassignedRowHeight="RowHeight(hasUnassigned ? grouped[_unassignedKey].Count : 1)"> + UnassignedRowHeight="RowHeight(hasUnassignedEvents ? unassignedLanes.Count : 1)">And at Line 131-133:
- `@if` (hasUnassigned) + `@if` (hasUnassignedEvents) { - `@RenderLanes`(grouped[_unassignedKey]) + `@RenderLanes`(unassignedLanes) }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razor` around lines 30 - 39, In BitFcTimelineDayView.razor, the UnassignedRowHeight logic is indexing grouped[_unassignedKey] even when hasUnassigned is true because resourceIds.Count == 0, which can crash on an empty calendar. Update the BitFcTimelineLayout usage and the related unassigned-row height calculation to separate the “render unassigned row” condition from the actual unassigned lane collection, and only access grouped[_unassignedKey] after confirming that key exists (or fall back to a safe default). Make the same guard wherever the unassigned group is read so render paths in this component do not assume the key is present.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razor (1)
9-21: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winKeep Event mode reachable when resources become empty.
Line 9 still hides the entire mode switch, so a calendar already in
Timelinemode can get stuck there onceResourcesbecomes empty because the Event tab disappears too.Suggested fix
-@if (State.Resources.Count > 0) -{ - <div class="bit-bfc-mode-tabs"> - `@foreach` (var mode in _modes) - { - <button class="bit-bfc-mode-tab @(State.Mode == mode ? "active" : "")" - type="button" - `@onclick`="() => State.SetMode(mode)"> - `@Texts.GetModeLabel`(mode) - </button> - } - </div> -} +<div class="bit-bfc-mode-tabs"> + `@foreach` (var mode in _modes) + { + if (mode is BitFullCalendarMode.Timeline && State.Resources.Count == 0) continue; + + <button class="bit-bfc-mode-tab @(State.Mode == mode ? "active" : "")" + type="button" + `@onclick`="() => State.SetMode(mode)"> + `@Texts.GetModeLabel`(mode) + </button> + } +</div>🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razor` around lines 9 - 21, The mode tab rendering in BitFcModeTabs is gated by State.Resources.Count > 0, which hides the entire switch when resources are empty and can trap the calendar in Timeline mode. Update the conditional rendering so the mode tabs still show at least the Event mode (and any needed fallback) when State.Resources is empty, while keeping the existing mode selection behavior in the _modes loop and State.SetMode(mode) intact.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razor.cs`:
- Around line 27-32: Start the toast expiration timer only after the toast has
been queued into the UI update. In BitFcCalendarToast.razor.cs, adjust the logic
around the InvokeAsync add and RemoveAfterDelay so the delay begins once
_toasts.Add(item) has actually run, not immediately after scheduling it. Use the
existing BitFcCalendarToast flow and the item.Id/cts handling to keep the timer
tied to the real add operation.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventDetailsDialog.razor`:
- Around line 3-4: The modal markup in BitFcEventDetailsDialog should trap
keyboard focus and restore it on close, since role="dialog" and aria-modal alone
do not keep focus inside the dialog. Update the dialog component logic around
the bit-bfc-dialog container to move focus into the modal when it opens, keep
tab navigation contained while it is visible, and return focus to the previously
focused element in OnClose or the corresponding close path.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razor`:
- Around line 3-4: The BitFcEventListDialog modal is missing proper focus
management, so keyboard users can tab out of the dialog and lose modal behavior.
Update the BitFcEventListDialog.razor dialog flow to move focus into the dialog
when it opens, trap tab navigation within the .bit-bfc-dialog while it is
visible, and restore focus to the previously focused element when OnClose runs.
Use the dialog container and its open/close lifecycle to wire this behavior.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razor`:
- Line 12: The toggle buttons in BitFcSettings.razor are binding aria-pressed to
booleans, which causes the attribute to disappear when false; update each of the
six button bindings to emit explicit "true" or "false" string values instead.
Apply this change consistently to the button markup that uses
State.BadgeVariant, State.SizeVariant, State.ShowWeekNumbers, State.IsRtl,
State.IsDarkMode, and State.IsCompact so assistive technologies always see a
valid ARIA state.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razor`:
- Around line 61-66: The week view half-slot in BitFcCalendarWeekView is only
configured for drag/drop, so it is neither clickable nor keyboard-accessible and
its events bubble up to the hour row. Update the :30 slot markup in the week
view to match the day view behavior by adding its own click and keyboard
handlers that call the existing slot handler with minute 30, and ensure
propagation is stopped so it does not fall through to the parent hour click.
Also add the accessibility attributes used in the day view, including role,
tabindex, and aria-label, to make the :30 target operable for keyboard users.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razor.cs`:
- Around line 37-58: Week view is still using hour-only add-event handlers, so
it cannot preserve minute precision for half-hour slots. Update
BitFcCalendarWeekView’s OnHourClickAsync and OnHourKeyDownAsync to accept and
forward minute, and pass that minute into
BitFullCalendarHelpers.CreateDraftEventForTimeSlot so the week view matches the
day view behavior. Also make sure the week view markup for the :30 slot wires
the same minute value into these handlers, not just the hour.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razor`:
- Around line 37-38: The BitFcEventBlock.razor event container is missing
keyboard event propagation रोक stopPropagation, so focused event key presses
bubble into parent OnHourKeyDownAsync handlers in BitFcCalendarWeekView and
BitFcCalendarDayView. Update the same element that already uses
`@onclick`:stopPropagation="true" to also stop propagation for `@onkeydown`,
matching the click behavior so Enter/Space on the event block do not trigger the
parent key handlers.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcDayCell.razor.cs`:
- Around line 44-48: The “more” trigger in BitFcDayCell still lets Spacebar
perform its default scroll behavior because OnMoreKeyDown only toggles
_showEventList. Update the BitFcDayCell.razor markup for the bit-bfc-month-more
element to prevent default on keydown, or set e.PreventDefault in OnMoreKeyDown,
so keyboard activation via Space/Enter opens the list without scrolling the
page.
---
Duplicate comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.scss`:
- Line 3: The FullCalendar SCSS import is using a file extension that violates
the stylesheet lint rule. Update the import in BitFullCalendar.scss to use the
partial-style path without the .scss suffix, keeping the reference to
functions.scss otherwise unchanged so stylelint passes.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razor`:
- Around line 9-21: The mode tab rendering in BitFcModeTabs is gated by
State.Resources.Count > 0, which hides the entire switch when resources are
empty and can trap the calendar in Timeline mode. Update the conditional
rendering so the mode tabs still show at least the Event mode (and any needed
fallback) when State.Resources is empty, while keeping the existing mode
selection behavior in the _modes loop and State.SetMode(mode) intact.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razor`:
- Around line 30-39: In BitFcTimelineDayView.razor, the UnassignedRowHeight
logic is indexing grouped[_unassignedKey] even when hasUnassigned is true
because resourceIds.Count == 0, which can crash on an empty calendar. Update the
BitFcTimelineLayout usage and the related unassigned-row height calculation to
separate the “render unassigned row” condition from the actual unassigned lane
collection, and only access grouped[_unassignedKey] after confirming that key
exists (or fall back to a safe default). Make the same guard wherever the
unassigned group is read so render paths in this component do not assume the key
is present.
In `@src/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scss`:
- Line 7: The new bundle import in extra-components.scss still includes the
.scss extension and triggers the stylesheet lint rule. Update the top-level
import for BitFullCalendar to use the partial-style path without the extension,
keeping the import in extra-components.scss aligned with the bundle conventions.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 18cf26cf-ba52-4773-8438-f41125a79919
📒 Files selected for processing (100)
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarBody.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarBody.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.scsssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcAddEditEventDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcAddEditEventDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventDetailsDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventDetailsDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarAgendaGroupBy.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarBadgeVariant.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarEventLayout.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarMode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarView.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcDateNavigator.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcDateNavigator.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcFilterEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcFilterEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcTodayButton.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcTodayButton.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcViewTabs.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcViewTabs.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarAttendee.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarCell.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarChangeEventArgs.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorOption.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorScheme.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarDateChangeEventArgs.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarResource.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarSettings.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarTexts.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcAgendaScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcTimeGridScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcTimelineScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarChangeNotifier.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarHelpers.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarState.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcDayViewMultiDayEventsRow.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcDayViewMultiDayEventsRow.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcRenderGroupedEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcRenderGroupedEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcTimeColumn.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcTimeColumn.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcCalendarMonthView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcCalendarMonthView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcDayCell.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcDayCell.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcEventBullet.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcEventBullet.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcMonthEventBadge.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcMonthEventBadge.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineLayout.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineLayout.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scsssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razor.cssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/ComponentsSection.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/MainLayout.razor.NavItems.cs
|
@coderabbitai re-review |
|
✅ Action performedFull review finished. |
There was a problem hiding this comment.
Actionable comments posted: 9
♻️ Duplicate comments (12)
src/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scss (1)
7-7:⚠️ Potential issue | 🟠 MajorRemove the
.scssextension from this bundle import.Line 7 still violates
scss/load-partial-extension, so the extras stylesheet bundle keeps the same lint blocker.Suggested fix
-@import "../Components/FullCalendar/BitFullCalendar.scss"; +@import "../Components/FullCalendar/BitFullCalendar";🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scss` at line 7, The stylesheet bundle import still includes the .scss extension, which violates the SCSS partial import rule. Update the import in extra-components.scss to use the partial name for BitFullCalendar.scss without the extension, keeping the existing bundle structure intact and ensuring the import path still points to the same FullCalendar stylesheet partial.src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razor.cs (1)
942-949:⚠️ Potential issue | 🟡 MinorRemove the
Default*attributes from the copied binding snippet.The live demo no longer uses
DefaultView,DefaultMode, orDefaultDatewith boundView/Mode/Date, butexample7RazorCodestill does. Those defaults never participate once the parameters are bound, so the copied sample is now misleading.Suggested fix
<BitFullCalendar Events=""events"" Resources=""resources"" - DefaultView=""BitFullCalendarView.Week"" - DefaultMode=""BitFullCalendarMode.Event"" - DefaultDate=""DateTime.Today"" `@bind-View`=""bindingView"" `@bind-Mode`=""bindingMode"" `@bind-Date`=""bindingDate""🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razor.cs` around lines 942 - 949, The copied BitFullCalendar demo snippet is still setting DefaultView, DefaultMode, and DefaultDate alongside the bound View, Mode, and Date properties, which makes the sample misleading. Update the example in BitFullCalendarDemo to remove those Default* attributes from the bound usage so the snippet matches the live demo behavior, and keep the bindings to bindingView, bindingMode, and bindingDate as the source of truth.src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razor (1)
113-146:⚠️ Potential issue | 🟠 MajorPrevent unsupported Timeline + Year/Agenda states.
This sample still binds
bindingViewandbindingModeindependently, so users can pickYearorAgendaand then switch toTimeline, but this PR only ships timeline day/week/month views. Filter the available views whenbindingMode == Timeline, or coercebindingViewback to a supported value in the mode/view change flow. Please mirror the same fix inexample7RazorCodetoo.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razor` around lines 113 - 146, The FullCalendar demo currently allows unsupported view/mode combinations because BitFullCalendarDemo.razor binds bindingView and bindingMode independently. Update the view/mode change flow in BitFullCalendarDemo.razor so that when bindingMode is Timeline, bindingView is limited or coerced to supported timeline views only, using the existing HandleViewChange and HandleModeChange logic. Apply the same constraint in example7RazorCode so both samples stay consistent.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.scss (1)
3-3:⚠️ Potential issue | 🟠 MajorRemove the
.scssextension from this import.Line 3 still violates
scss/load-partial-extension, so Stylelint stays red until this is imported asfunctions.Suggested fix
-@import "../../../Bit.BlazorUI/Styles/functions.scss"; +@import "../../../Bit.BlazorUI/Styles/functions";🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.scss` at line 3, The import in BitFullCalendar.scss still includes the .scss extension, which violates the scss/load-partial-extension rule. Update the `@import` for functions.scss to use the partial name only, keeping the same relative path but removing the extension so Stylelint passes.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razor.cs (1)
58-89: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick winLet
RemoveAfterDelayown CTS disposal.This is still vulnerable to the earlier disposal race:
Show()starts the timer asynchronously, but Line 88 can dispose itsCancellationTokenSourcefirst. If the queued removal path then reaches Line 44 and touchescts.Token, it can fail withObjectDisposedException.Proposed fix
finally { - bool removed; lock (_removalTokensLock) { - removed = _removalTokens.Remove(cts); + _removalTokens.Remove(cts); } - if (removed) - cts.Dispose(); + cts.Dispose(); } } @@ foreach (var cts in tokens) { - try - { - cts.Cancel(); - cts.Dispose(); - } - catch (ObjectDisposedException) - { - // Already disposed by RemoveAfterDelay's cleanup; nothing to do. - } + cts.Cancel(); }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razor.cs` around lines 58 - 89, The CTS disposal ownership is still split between DisposeAsync and RemoveAfterDelay, which can race with the async timer started by Show(). Update BitFcCalendarToast so RemoveAfterDelay is the only place that cancels/disposes each CancellationTokenSource, and make DisposeAsync only snapshot and request removal without disposing the tokens directly. Keep the cleanup logic centered in RemoveAfterDelay and the _removalTokens bookkeeping so the queued path never touches a CTS after another caller has disposed it.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cs (2)
8-9: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick winEnforce
EndDate >= StartDateat the model boundary.Lines 8-9 still allow inverted ranges. Helpers like
GetInclusiveEndDate,GroupEvents, and the day/month overlap filters assume a forward interval, so a negative-duration event can be grouped and rendered incorrectly across views. Reject invalid ranges when either endpoint is assigned.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cs` around lines 8 - 9, `BitFullCalendarEvent` currently allows invalid date ranges because `StartDate` and `EndDate` can be set independently without validation. Update the model boundary so `EndDate` is never earlier than `StartDate`, ideally by adding validation in the `StartDate`/`EndDate` property setters or a shared range-checking helper on `BitFullCalendarEvent`. Make sure any assignment path rejects inverted ranges before helpers like `GetInclusiveEndDate`, `GroupEvents`, and the overlap filters consume the event.
5-5: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy liftRequire a stable event key before month layout is built.
Line 5 still defaults
Idtostring.Empty, while month placement stores positions by rawev.IdinBitFullCalendarHelpers.CalculateMonthEventPositionsand reads them back inGetMonthCellEvents. Missing or duplicate ids overwrite each other, so one event can steal another event's month-row slot. Please normalize/reject missing ids before layout state is built, or stop keying that state by rawId.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cs` at line 5, The month layout logic currently keys placement state by raw event Id, so BitFullCalendarEvent.Id must be stable before BitFullCalendarHelpers.CalculateMonthEventPositions and GetMonthCellEvents run. Update the BitFullCalendarEvent model and/or the month-layout flow to reject or normalize empty or duplicate Id values before building layout state, or change the placement dictionary to use a guaranteed unique key instead of raw Id. Ensure the fix is applied where BitFullCalendarEvent.Id is initialized and where month event positions are stored and retrieved.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorScheme.cs (1)
21-35:⚠️ Potential issue | 🟡 MinorNormalize the stored option IDs too.
_byIdresolves the trimmed id, butOptionsstill keeps the original objects. An input like" blue "will therefore resolve viaFind("blue")while downstream consumers ofOptionsstill see" blue ", so the exposed palette can drift from the resolver. Build both collections from normalizedBitFullCalendarColorOptioninstances.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorScheme.cs` around lines 21 - 35, The canonicalization in BitFullCalendarColorScheme currently trims and deduplicates ids for the _byId lookup but still stores the original BitFullCalendarColorOption objects in Options, so downstream consumers can see unnormalized ids. Update the construction logic around the canonical list and _byId population so both collections are built from normalized option instances (with trimmed ids), keeping Options, Find, and any UI/filter consumers aligned.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarState.cs (2)
44-47:⚠️ Potential issue | 🟠 MajorStop rewriting IDs on caller-owned event instances.
Initialize,SyncEvents, andAddEventkeep the originalBitFullCalendarEventobjects, thenNormalizeEventIdsmutatesev.Id. That leaks internal normalization back across the component boundary and can surprise any parent code holding the same models. Normalize on component-owned copies, or keep a separate internal key.Also applies to: 224-225, 281-285, 469-494
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarState.cs` around lines 44 - 47, Stop mutating caller-owned BitFullCalendarEvent instances when normalizing IDs. Update Initialize, SyncEvents, and AddEvent in BitFullCalendarState so they work on component-owned copies or use a separate internal key instead of calling NormalizeEventIds on the original objects. Keep the normalization logic isolated inside BitFullCalendarState and make sure any place that currently sets ev.Id only affects internal state, not the list or event objects passed in by the caller.
12-12:⚠️ Potential issue | 🟠 MajorUse a browser-local “today” source.
Both the initial state and
GoToTodayuseDateTime.Today, which comes from the server clock in Blazor Server. Users in other time zones can land on the wrong day unless this value is supplied from browser-local time.Also applies to: 199-205
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarState.cs` at line 12, The SelectedDate state in BitFullCalendarState is using server-local DateTime.Today, which can be wrong for Blazor Server users in other time zones. Update the initial SelectedDate value and the GoToToday path to source “today” from the browser/client time instead of the server clock, and keep the logic centralized in BitFullCalendarState so both initialization and today navigation use the same browser-local value.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcRenderGroupedEvents.razor (1)
14-35:⚠️ Potential issue | 🟠 MajorUse peak concurrency for
depth, not lane intersection count.This still counts every lane that intersects
evat any point, so staggered conflicts shrink events more than they should. Derivedepthfrom the maximum number of simultaneous overlaps withinev's own time range, then computerankfrom that active set instead of all intersecting lanes.Also applies to: 40-57
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcRenderGroupedEvents.razor` around lines 14 - 35, The grouped event sizing logic in BitFcRenderGroupedEvents should not derive `depth` from the number of lanes that merely intersect `ev`; use peak simultaneous overlap within the event’s own time range instead. Update the overlap calculation around `GroupedEvents`, `leftConflicts`, `rightConflicts`, `depth`, and `rank` so the active set is based on maximum concurrency at each moment, then compute `rank` from that same active overlap set rather than all intersecting lanes.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razor.cs (1)
20-28: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick winStill missing the earlier JS interop exception guard.
This remains unresolved from the prior review: a transient
JSException/disconnect duringTryScrollToDateAsynccan still fault the render path because the await is unguarded.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razor.cs` around lines 20 - 28, The OnAfterRenderAsync flow in BitFcAgendaEvents still awaits BitFcAgendaScrollInterop.TryScrollToDateAsync without handling transient JS failures. Update OnAfterRenderAsync to catch and safely ignore expected JS interop disconnect/JSException cases around the await, while still preserving the existing nonce check and only setting _lastAgendaScrollNonce when scrolling succeeds.
🧹 Nitpick comments (1)
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razor (1)
17-22: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winReuse
BitFullCalendarHelpers.GetInclusiveEndDatehere too.This markup now carries its own copy of the exclusive-midnight normalization while the row-placement path already centralizes that rule in the helper. Keeping both call sites on the helper will make the next date-edge-case fix land in one place instead of two.
Suggested refactor
- var evEndInclusive = (ev.EndDate > ev.StartDate ? ev.EndDate.AddTicks(-1) : ev.EndDate).Date; + var evEndInclusive = BitFullCalendarHelpers.GetInclusiveEndDate(ev).Date;🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razor` around lines 17 - 22, The multi-day event badge logic in BitFcWeekViewMultiDayEventsRow duplicates the exclusive-midnight end-date normalization instead of reusing the shared helper. Replace the local end-date adjustment and comparison with BitFullCalendarHelpers.GetInclusiveEndDate so the position calculation ("first", "last", "middle") follows the same rule as the row-placement path and stays centralized in one place.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razor`:
- Line 5: The BitFcDateTimePicker trigger currently binds aria-expanded to a
boolean, which causes the attribute to be omitted when the picker is closed;
update the trigger markup in BitFcDateTimePicker so aria-expanded is always
rendered as an explicit string value reflecting _isOpen. Keep the change
localized to the button with class bit-bfc-dtp-trigger and ensure
GetTriggerAriaLabel remains unchanged while the expanded state is exposed
consistently for screen readers.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventDetailsDialog.razor.cs`:
- Around line 56-75: The delete flow in BitFcEventDetailsDialog currently
removes the event before both awaited callbacks finish, so a retry after a
partial failure can emit a second Delete for the same item. Update the delete
handler around the snapshot/State.RemoveEvent/Notifier.NotifyAsync/OnClose
sequence to track whether the local delete has already been committed, and
prevent re-sending the delete notification if a previous attempt removed the
event but failed later. Use the existing _isDeleting guard in the dialog method
to keep the UI retryable without allowing duplicate delete emissions.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razor`:
- Around line 11-18: The mode switcher in BitFcModeTabs currently exposes the
active state only through CSS, so update the container and buttons to match the
accessibility pattern used by BitFcViewTabs. Add a tablist role to the wrapper
in BitFcModeTabs and give each mode button a tab role with an aria-selected
state that reflects whether State.Mode matches the current mode. Keep the
existing State.SetMode(mode) behavior and Texts.GetModeLabel(mode) labeling
unchanged.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razor.cs`:
- Around line 16-18: The `BitFcAgendaEvents` component subscribes to
`State.OnStateChanged` in `OnInitialized`, but its `Dispose` method will not be
called unless the class implements `IDisposable`. Update `BitFcAgendaEvents` to
implement `IDisposable` so the Blazor runtime invokes `Dispose`, and keep the
existing unsubscription logic there to detach `Refresh` from
`State.OnStateChanged` when the component is destroyed.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razor`:
- Around line 93-105: The “Happening now” button in BitFcCalendarDayView.razor
uses block-level divs inside a button, which breaks valid button content and can
affect browser/accessibility behavior. Update the markup in the event button
rendering to use phrasing elements such as spans for the title and meta rows,
keeping the SelectEvent(ev) click behavior unchanged and preserving the existing
ev.Title, ev.Attendees, and BitFullCalendarHelpers.FormatTime content.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razor`:
- Around line 48-73: The slot pseudo-buttons in BitFcCalendarWeekView use
OnHourKeyDownAsync for activation, but Space still scrolls the page because the
keydown handlers do not prevent default behavior. Update both the full-hour and
30-minute slot `@onkeydown` handlers in the week view markup to include the
prevent-default modifier, keeping the existing OnHourKeyDownAsync logic
unchanged.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razor.cs`:
- Around line 52-58: The BitFcEventBlock.OnKeyDown handler currently fires
OnSelected on every Enter/Space keydown, including repeated keydown events, so
update it to ignore e.Repeat the same way the month badge logic does. Keep the
existing _isResizing guard, then add a repeated-keydown check before invoking
OnSelected so holding the key cannot trigger multiple selections for the same
Event.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razor`:
- Around line 84-93: The focusable slot cells in BitFcTimelineMonthView,
BitFcTimelineDayView, and BitFcTimelineWeekView use divs with role="button",
which lets Space trigger page scrolling instead of native button behavior.
Replace these slot cell divs with native button elements (type="button") in the
relevant slot cell markup blocks, keeping the existing CSS classes, drag/drop
handlers, aria-label, and click actions intact. This will remove the custom
keyboard handling around OnSlotKeyDownAsync and give correct Space/Enter
semantics automatically.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razor`:
- Around line 112-130: The slot hit targets in BitFcTimelineWeekView are `div`
elements with `role="button"` and `@onkeydown`, so Space still scrolls the page
instead of activating the slot. Update the interactive slot markup to use native
`<button type="button">` elements in the timeline cell blocks, and keep the
existing handlers like `OnSlotClickAsync`, `OnSlotKeyDownAsync`, `OnDragEnter`,
and `OnDrop` wired up. After replacing the elements, adjust any CSS affected by
button default styling so the visual layout stays unchanged.
---
Duplicate comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razor.cs`:
- Around line 58-89: The CTS disposal ownership is still split between
DisposeAsync and RemoveAfterDelay, which can race with the async timer started
by Show(). Update BitFcCalendarToast so RemoveAfterDelay is the only place that
cancels/disposes each CancellationTokenSource, and make DisposeAsync only
snapshot and request removal without disposing the tokens directly. Keep the
cleanup logic centered in RemoveAfterDelay and the _removalTokens bookkeeping so
the queued path never touches a CTS after another caller has disposed it.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.scss`:
- Line 3: The import in BitFullCalendar.scss still includes the .scss extension,
which violates the scss/load-partial-extension rule. Update the `@import` for
functions.scss to use the partial name only, keeping the same relative path but
removing the extension so Stylelint passes.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorScheme.cs`:
- Around line 21-35: The canonicalization in BitFullCalendarColorScheme
currently trims and deduplicates ids for the _byId lookup but still stores the
original BitFullCalendarColorOption objects in Options, so downstream consumers
can see unnormalized ids. Update the construction logic around the canonical
list and _byId population so both collections are built from normalized option
instances (with trimmed ids), keeping Options, Find, and any UI/filter consumers
aligned.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cs`:
- Around line 8-9: `BitFullCalendarEvent` currently allows invalid date ranges
because `StartDate` and `EndDate` can be set independently without validation.
Update the model boundary so `EndDate` is never earlier than `StartDate`,
ideally by adding validation in the `StartDate`/`EndDate` property setters or a
shared range-checking helper on `BitFullCalendarEvent`. Make sure any assignment
path rejects inverted ranges before helpers like `GetInclusiveEndDate`,
`GroupEvents`, and the overlap filters consume the event.
- Line 5: The month layout logic currently keys placement state by raw event Id,
so BitFullCalendarEvent.Id must be stable before
BitFullCalendarHelpers.CalculateMonthEventPositions and GetMonthCellEvents run.
Update the BitFullCalendarEvent model and/or the month-layout flow to reject or
normalize empty or duplicate Id values before building layout state, or change
the placement dictionary to use a guaranteed unique key instead of raw Id.
Ensure the fix is applied where BitFullCalendarEvent.Id is initialized and where
month event positions are stored and retrieved.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarState.cs`:
- Around line 44-47: Stop mutating caller-owned BitFullCalendarEvent instances
when normalizing IDs. Update Initialize, SyncEvents, and AddEvent in
BitFullCalendarState so they work on component-owned copies or use a separate
internal key instead of calling NormalizeEventIds on the original objects. Keep
the normalization logic isolated inside BitFullCalendarState and make sure any
place that currently sets ev.Id only affects internal state, not the list or
event objects passed in by the caller.
- Line 12: The SelectedDate state in BitFullCalendarState is using server-local
DateTime.Today, which can be wrong for Blazor Server users in other time zones.
Update the initial SelectedDate value and the GoToToday path to source “today”
from the browser/client time instead of the server clock, and keep the logic
centralized in BitFullCalendarState so both initialization and today navigation
use the same browser-local value.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razor.cs`:
- Around line 20-28: The OnAfterRenderAsync flow in BitFcAgendaEvents still
awaits BitFcAgendaScrollInterop.TryScrollToDateAsync without handling transient
JS failures. Update OnAfterRenderAsync to catch and safely ignore expected JS
interop disconnect/JSException cases around the await, while still preserving
the existing nonce check and only setting _lastAgendaScrollNonce when scrolling
succeeds.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcRenderGroupedEvents.razor`:
- Around line 14-35: The grouped event sizing logic in BitFcRenderGroupedEvents
should not derive `depth` from the number of lanes that merely intersect `ev`;
use peak simultaneous overlap within the event’s own time range instead. Update
the overlap calculation around `GroupedEvents`, `leftConflicts`,
`rightConflicts`, `depth`, and `rank` so the active set is based on maximum
concurrency at each moment, then compute `rank` from that same active overlap
set rather than all intersecting lanes.
In `@src/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scss`:
- Line 7: The stylesheet bundle import still includes the .scss extension, which
violates the SCSS partial import rule. Update the import in
extra-components.scss to use the partial name for BitFullCalendar.scss without
the extension, keeping the existing bundle structure intact and ensuring the
import path still points to the same FullCalendar stylesheet partial.
In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razor`:
- Around line 113-146: The FullCalendar demo currently allows unsupported
view/mode combinations because BitFullCalendarDemo.razor binds bindingView and
bindingMode independently. Update the view/mode change flow in
BitFullCalendarDemo.razor so that when bindingMode is Timeline, bindingView is
limited or coerced to supported timeline views only, using the existing
HandleViewChange and HandleModeChange logic. Apply the same constraint in
example7RazorCode so both samples stay consistent.
In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razor.cs`:
- Around line 942-949: The copied BitFullCalendar demo snippet is still setting
DefaultView, DefaultMode, and DefaultDate alongside the bound View, Mode, and
Date properties, which makes the sample misleading. Update the example in
BitFullCalendarDemo to remove those Default* attributes from the bound usage so
the snippet matches the live demo behavior, and keep the bindings to
bindingView, bindingMode, and bindingDate as the source of truth.
---
Nitpick comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razor`:
- Around line 17-22: The multi-day event badge logic in
BitFcWeekViewMultiDayEventsRow duplicates the exclusive-midnight end-date
normalization instead of reusing the shared helper. Replace the local end-date
adjustment and comparison with BitFullCalendarHelpers.GetInclusiveEndDate so the
position calculation ("first", "last", "middle") follows the same rule as the
row-placement path and stays centralized in one place.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 53f13e8a-6115-4ecb-a4cb-f1500222d9a5
📒 Files selected for processing (101)
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarBody.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarBody.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.scsssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcAddEditEventDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcAddEditEventDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventDetailsDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventDetailsDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarAgendaGroupBy.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarBadgeVariant.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarEventLayout.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarMode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarView.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcDateNavigator.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcDateNavigator.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcFilterEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcFilterEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcTodayButton.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcTodayButton.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcViewTabs.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcViewTabs.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarAttendee.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarCell.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarChangeEventArgs.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorOption.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorScheme.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarDateChangeEventArgs.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarResource.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarSettings.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarTexts.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcAgendaScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcDialogInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcTimeGridScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcTimelineScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarChangeNotifier.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarHelpers.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarState.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcDayViewMultiDayEventsRow.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcDayViewMultiDayEventsRow.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcRenderGroupedEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcRenderGroupedEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcTimeColumn.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcTimeColumn.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcCalendarMonthView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcCalendarMonthView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcDayCell.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcDayCell.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcEventBullet.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcEventBullet.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcMonthEventBadge.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcMonthEventBadge.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineLayout.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineLayout.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scsssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razor.cssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/ComponentsSection.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/MainLayout.razor.NavItems.cs
|
@coderabbitai re-review |
|
✅ Action performedFull review finished. |
There was a problem hiding this comment.
Actionable comments posted: 3
♻️ Duplicate comments (4)
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razor (1)
30-39: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
grouped[_unassignedKey]can throwKeyNotFoundExceptionon an empty calendar.
hasUnassignedbecomestruewhenresourceIds.Count == 0, even ifgroupedhas no_unassignedKeyentry (no events). Line 39 and Line 133 then indexgrouped[_unassignedKey]directly and throw. The week view already avoids this via the safeLaneCountFor/TryGetValuepath; the day view should do the same. This matches the still-open prior finding.🛡️ Proposed fix
- var hasUnassigned = (grouped.TryGetValue(_unassignedKey, out var u) && u.Count > 0) || resourceIds.Count == 0; + var hasUnassignedEvents = grouped.TryGetValue(_unassignedKey, out var u) && u.Count > 0; + var hasUnassigned = hasUnassignedEvents || resourceIds.Count == 0; var scrollHour = State.StartOfDayHour; } <BitFcTimelineLayout ColumnCount="24" ColumnWidthPx="hourWidth" ScrollContainerId="`@_scrollContainerId`" HasUnassignedRow="hasUnassigned" RowHeightFor="r => RowHeight(LaneCountFor(r.Id))" - UnassignedRowHeight="RowHeight(hasUnassigned ? grouped[_unassignedKey].Count : 1)"> + UnassignedRowHeight="RowHeight(LaneCountFor(_unassignedKey))">And guard the lane render at Line 131-133:
- `@if` (hasUnassigned) + `@if` (hasUnassignedEvents) { - `@RenderLanes`(grouped[_unassignedKey]) + `@RenderLanes`(u) }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razor` around lines 30 - 39, The Day view’s unassigned row logic can still throw when `grouped[_unassignedKey]` is accessed without verifying the key exists, especially when `resourceIds.Count == 0` and there are no events. Update `BitFcTimelineDayView` to use the same safe `TryGetValue`/`LaneCountFor` pattern already used in the week view, and make `UnassignedRowHeight` depend on a guarded unassigned-lane count instead of directly indexing `grouped[_unassignedKey]`. Also review the unassigned lane render path in `BitFcTimelineLayout` usage so it only reads the unassigned group when the key is present.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razor.cs (1)
111-134: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
OnResizeMovestill treats the interop delta as pixels — confirm the JS unit contract.A prior review flagged that
BitFullCalendar.tspassesdeltaMinutes, yetOnResizeMovestill names the parameterdeltaPx, compares it toDeadZonePx(a pixel value), and divides byPixelsPerMinuteagain at Line 134. If the JS side really sends minutes, the dead-zone gate and committed range will be wrong. If JS sends pixels, the code is correct and the concern is moot — so the unit on both sides needs to be confirmed end-to-end.#!/bin/bash # Inspect what initResizeHorizontal sends to OnResizeMove (pixels vs minutes) fd -t f 'BitFullCalendar.ts' --exec cat -n {}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razor.cs` around lines 111 - 134, `OnResizeMove` may be using the wrong unit for the resize delta, so confirm the contract with `BitFullCalendar.ts` and `initResizeHorizontal` end-to-end. Check whether the interop payload is pixels or minutes, then make `OnResizeMove` consistent with that unit by updating the parameter naming, dead-zone comparison against `DeadZonePx`, and the `PixelsPerMinute` conversion logic if needed. Use `OnResizeMove`, `DeadZonePx`, and `PixelsPerMinute` to align both the Blazor handler and the TS sender.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarChangeNotifier.cs (1)
88-95: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick winGuard
Attendeesbefore cloning.
source.Attendeesis consumer-populated and can benull;.Select(...)will throw an NRE while raising drag/edit notifications. This was previously flagged and is still unguarded in the current code.Proposed fix
- Attendees = source.Attendees - .Select(a => new BitFullCalendarAttendee - { - FirstName = a.FirstName, - LastName = a.LastName, - Id = a.Id - }) - .ToList() + Attendees = source.Attendees? + .Select(a => new BitFullCalendarAttendee + { + FirstName = a.FirstName, + LastName = a.LastName, + Id = a.Id + }) + .ToList() ?? []🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarChangeNotifier.cs` around lines 88 - 95, The attendee cloning in BitFullCalendarChangeNotifier still assumes source.Attendees is always present, which can throw during drag/edit notifications. Update the notification-building logic in the cloning path that projects attendees with Select to first handle a null Attendees collection, using a safe fallback before mapping to BitFullCalendarAttendee instances. Keep the fix localized to the attendee copy block so the rest of the change notification flow remains unchanged.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razor.cs (1)
3-18: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick winConfirm
IDisposableis declared so theState.OnStateChangedunsubscription runs.The class subscribes in
OnInitializedand unsubscribes inDispose(Line 18), but the class declaration here does not implementIDisposable. Blazor only invokesDisposeif the component implementsIDisposable(commonly via@implements IDisposablein the.razor, as done inBitFcCalendarTimeline.razor). If neither the partial nor the markup declares it, the handler leaks and may fire on a disposed instance.#!/bin/bash # Check whether BitFcAgendaEvents declares IDisposable (in partial or razor) and how JS is injected. fd -t f 'BitFcAgendaEvents.razor' --exec sh -c 'echo "== {} =="; cat -n "{}"' rg -nP 'class\s+BitFcAgendaEvents|IDisposable|`@implements`|`@inject`' \ src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razor.cs` around lines 3 - 18, The component subscribes to State.OnStateChanged in OnInitialized and unsubscribes in Dispose, but BitFcAgendaEvents does not currently declare IDisposable, so Blazor may never call Dispose. Update the BitFcAgendaEvents partial component so it implements IDisposable consistently with the matching .razor file pattern used elsewhere, ensuring the Refresh handler is reliably removed when the component is torn down.
🧹 Nitpick comments (1)
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcDayViewMultiDayEventsRow.razor.cs (1)
25-26: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winCompare the inclusive end day explicitly.
This method is choosing a day bucket, but Line 26 compares the full
DateTime. UsingendInclusive.Datekeeps"last"independent of whether the helper preserves a time component.Proposed fix
- if (endInclusive == Date.Date) return "last"; + if (endInclusive.Date == Date.Date) return "last";🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcDayViewMultiDayEventsRow.razor.cs` around lines 25 - 26, The day-bucket selection in BitFcDayViewMultiDayEventsRow.GetDayClass currently compares the helper result as a full DateTime, which can make the "last" class depend on time components. Update the comparison to explicitly use the date part from endInclusive when checking against Date.Date, so the logic is based only on the calendar day and not any preserved time value.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razor.cs`:
- Around line 16-22: The `OnKeyDown` handler in `BitFcDraggableEvent` currently
fires `OnClick` on every repeated Enter/Space keydown, causing multiple
activations from a held key. Update `OnKeyDown(KeyboardEventArgs e)` to ignore
auto-repeat by adding the same `!e.Repeat` guard used in
`BitFcCalendarDayView.OnHourKeyDownAsync`, so only the first Enter/Space press
invokes `OnClick.InvokeAsync()`.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razor.cs`:
- Around line 210-220: The resize cleanup in BitFcEventBlock should always
trigger a render even if State.UpdateEvent or Notifier.NotifyAsync throws. Move
the InvokeAsync(StateHasChanged) call so it runs from the finally path in the
resize commit flow, alongside the field resets, ensuring the preview state is
cleared immediately after the operation fails or succeeds. Use the existing
resize commit logic in BitFcEventBlock and the update/notify sequence as the
location for the fix.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcDayCell.razor.cs`:
- Around line 30-37: The month-cell add flow is initializing the external draft
differently from the built-in dialog flow, so OnCellClick and the
BitFcAddEditEventDialog fallback can produce inconsistent start times. Update
OnCellClick in BitFcDayCell to use one shared draft-initialization path for both
the OnAddClick branch and the dialog branch, and avoid seeding the draft with
DateTime.Now.Hour so the selected cell date/time is consistent regardless of
consumer handling.
---
Duplicate comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarChangeNotifier.cs`:
- Around line 88-95: The attendee cloning in BitFullCalendarChangeNotifier still
assumes source.Attendees is always present, which can throw during drag/edit
notifications. Update the notification-building logic in the cloning path that
projects attendees with Select to first handle a null Attendees collection,
using a safe fallback before mapping to BitFullCalendarAttendee instances. Keep
the fix localized to the attendee copy block so the rest of the change
notification flow remains unchanged.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razor.cs`:
- Around line 3-18: The component subscribes to State.OnStateChanged in
OnInitialized and unsubscribes in Dispose, but BitFcAgendaEvents does not
currently declare IDisposable, so Blazor may never call Dispose. Update the
BitFcAgendaEvents partial component so it implements IDisposable consistently
with the matching .razor file pattern used elsewhere, ensuring the Refresh
handler is reliably removed when the component is torn down.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razor`:
- Around line 30-39: The Day view’s unassigned row logic can still throw when
`grouped[_unassignedKey]` is accessed without verifying the key exists,
especially when `resourceIds.Count == 0` and there are no events. Update
`BitFcTimelineDayView` to use the same safe `TryGetValue`/`LaneCountFor` pattern
already used in the week view, and make `UnassignedRowHeight` depend on a
guarded unassigned-lane count instead of directly indexing
`grouped[_unassignedKey]`. Also review the unassigned lane render path in
`BitFcTimelineLayout` usage so it only reads the unassigned group when the key
is present.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razor.cs`:
- Around line 111-134: `OnResizeMove` may be using the wrong unit for the resize
delta, so confirm the contract with `BitFullCalendar.ts` and
`initResizeHorizontal` end-to-end. Check whether the interop payload is pixels
or minutes, then make `OnResizeMove` consistent with that unit by updating the
parameter naming, dead-zone comparison against `DeadZonePx`, and the
`PixelsPerMinute` conversion logic if needed. Use `OnResizeMove`, `DeadZonePx`,
and `PixelsPerMinute` to align both the Blazor handler and the TS sender.
---
Nitpick comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcDayViewMultiDayEventsRow.razor.cs`:
- Around line 25-26: The day-bucket selection in
BitFcDayViewMultiDayEventsRow.GetDayClass currently compares the helper result
as a full DateTime, which can make the "last" class depend on time components.
Update the comparison to explicitly use the date part from endInclusive when
checking against Date.Date, so the logic is based only on the calendar day and
not any preserved time value.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 2b976cba-a6df-4847-861e-5827a8d47e15
📒 Files selected for processing (101)
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarBody.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarBody.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.scsssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcAddEditEventDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcAddEditEventDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventDetailsDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventDetailsDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarAgendaGroupBy.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarBadgeVariant.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarEventLayout.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarMode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarView.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcDateNavigator.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcDateNavigator.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcFilterEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcFilterEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcTodayButton.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcTodayButton.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcViewTabs.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcViewTabs.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarAttendee.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarCell.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarChangeEventArgs.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorOption.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorScheme.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarDateChangeEventArgs.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarResource.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarSettings.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarTexts.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcAgendaScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcDialogInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcTimeGridScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcTimelineScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarChangeNotifier.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarHelpers.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarState.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcDayViewMultiDayEventsRow.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcDayViewMultiDayEventsRow.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcRenderGroupedEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcRenderGroupedEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcTimeColumn.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcTimeColumn.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcCalendarMonthView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcCalendarMonthView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcDayCell.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcDayCell.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcEventBullet.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcEventBullet.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcMonthEventBadge.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcMonthEventBadge.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineLayout.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineLayout.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scsssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razor.cssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/ComponentsSection.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/MainLayout.razor.NavItems.cs
|
@coderabbitai re-review |
|
✅ Action performedFull review finished. |
There was a problem hiding this comment.
Actionable comments posted: 3
♻️ Duplicate comments (7)
src/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scss (1)
7-7: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick winRemove the
.scssextension from the FullCalendar import.Line 7 violates
scss/load-partial-extension; matches the existing partials above which omit the extension.Suggested fix
-@import "../Components/FullCalendar/BitFullCalendar.scss"; +@import "../Components/FullCalendar/BitFullCalendar";🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scss` at line 7, The FullCalendar import in extra-components.scss should follow the same partial-import style as the other SCSS imports. Update the `@import` statement that references BitFullCalendar to omit the .scss extension so it matches the existing load-partial-extension convention and stays consistent with the other partial imports in this stylesheet.Source: Linters/SAST tools
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.scss (1)
3-3: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick winDrop the
.scssextension from the partial import.Line 3 still violates
scss/load-partial-extension, keeping lint red. The keyframe-naming half of the earlier finding is resolved, but this import was not.✅ Suggested patch
-@import "../../../Bit.BlazorUI/Styles/functions.scss"; +@import "../../../Bit.BlazorUI/Styles/functions";🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.scss` at line 3, The remaining lint issue is in the partial import within BitFullCalendar.scss: the `@import` still includes the .scss extension, violating scss/load-partial-extension. Update the import statement in the FullCalendar stylesheet to reference the shared functions partial without the extension, and keep the existing path structure otherwise unchanged.Source: Linters/SAST tools
src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razor (1)
113-146: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winPrevent unsupported Timeline view combinations.
The binding demo still lets users keep/select
YearorAgendawhilebindingMode == Timeline, but this feature stack only implements timeline day/week/month layouts. Please either filter the view options in Timeline mode or coercebindingViewto a supported value when the mode changes; otherwise the live demo can enter an unsupported state, and the mirrored sample inexample7RazorCodestays misleading too.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razor` around lines 113 - 146, The FullCalendar demo allows unsupported view/mode combinations because BitFullCalendarDemo.razor binds all BitChoiceGroupOption<BitFullCalendarView> values even when bindingMode is BitFullCalendarMode.Timeline. Update the demo logic in the view/mode handlers (HandleModeChange and/or HandleViewChange) to either hide/disable Year and Agenda in Timeline mode or automatically coerce bindingView to a supported BitFullCalendarView when bindingMode changes. Also keep the mirrored example text in example7RazorCode aligned with this supported timeline behavior.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razor.cs (1)
114-125: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick winGuard the time-grid scroll interop against transient JS lifecycle failures.
TryScrollToStartOfDayAsyncis awaited on the render path without an exception guard. During prerender/disconnect/teardown this can throw and break the render. NoteBitFcAgendaEvents.razor.csalready wraps the equivalent interop call; this view should mirror that pattern and only advance_timeGridScrollSignatureon success.Suggested patch
- if (await BitFcTimeGridScrollInterop.TryScrollToStartOfDayAsync( - JS, - _scrollContainerId, - State.StartOfDayHour)) - _timeGridScrollSignature = sig; + try + { + if (await BitFcTimeGridScrollInterop.TryScrollToStartOfDayAsync( + JS, + _scrollContainerId, + State.StartOfDayHour)) + _timeGridScrollSignature = sig; + } + catch (Exception ex) when (ex is JSDisconnectedException or JSException or OperationCanceledException) + { + // Transient renderer/JS lifecycle condition; retry on a later render. + }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razor.cs` around lines 114 - 125, Guard the time-grid scroll interop in BitFcCalendarDayView.OnAfterRenderAsync against transient JS lifecycle failures, since TryScrollToStartOfDayAsync can throw during prerender/disconnect/teardown and currently breaks the render path. Mirror the error-handling pattern used in BitFcAgendaEvents.razor.cs by wrapping the await in a try/catch, swallowing or logging the expected JS failure, and only updating _timeGridScrollSignature when the scroll call succeeds. Keep the existing BuildTimeGridScrollSignature and _timeGridScrollSignature logic unchanged aside from advancing the signature after a successful interop call.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razor.cs (1)
99-110: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick winGuard the week-view time-grid scroll interop against transient JS failures.
Same issue as the day view: the awaited
TryScrollToStartOfDayAsyncon the render path has no transient-exception guard, so a disconnect/teardown can fail the render. Wrap it and only update_timeGridScrollSignatureon success, consistent with the agenda view.Suggested patch
- if (await BitFcTimeGridScrollInterop.TryScrollToStartOfDayAsync( - JS, - _timeGridScrollElementId, - State.StartOfDayHour)) - _timeGridScrollSignature = sig; + try + { + if (await BitFcTimeGridScrollInterop.TryScrollToStartOfDayAsync( + JS, + _timeGridScrollElementId, + State.StartOfDayHour)) + _timeGridScrollSignature = sig; + } + catch (Exception ex) when (ex is JSDisconnectedException or JSException or OperationCanceledException) + { + // Transient renderer/JS lifecycle condition; retry on a later render. + }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razor.cs` around lines 99 - 110, The week-view render path in OnAfterRenderAsync should guard the awaited BitFcTimeGridScrollInterop.TryScrollToStartOfDayAsync call against transient JS failures, just like the agenda view. Wrap the interop call in a transient-exception-safe pattern, and only assign _timeGridScrollSignature after a successful scroll; use the existing identifiers OnAfterRenderAsync, BitFcTimeGridScrollInterop.TryScrollToStartOfDayAsync, and _timeGridScrollSignature to make the fix consistent with the other view.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cs (1)
8-9: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winStill missing an event-range invariant.
EndDatecan still be set earlier thanStartDate, soDurationon Line 36 goes negative and invalid ranges still enter downstream state/layout code. EnforceEndDate >= StartDateat the model boundary instead of relying on callers.Also applies to: 34-36
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cs` around lines 8 - 9, The BitFullCalendarEvent model still allows invalid date ranges because EndDate can be set earlier than StartDate, which breaks Duration and downstream layout logic. Enforce the invariant at the model boundary by validating or normalizing in BitFullCalendarEvent’s StartDate/EndDate setters or constructor so EndDate is always greater than or equal to StartDate, and make sure Duration and any range-dependent members rely on this guaranteed ordering.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razor.cs (1)
27-49: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick winDisposal race can throw
ObjectDisposedExceptionfromcts.Token.
RemoveAfterDelayis scheduled inside theInvokeAsynccallback, butctsis registered before it. IfDisposeAsyncruns after the_removalTokens.Add(cts)but before the queued callback executes, it disposescts; the callback then callsRemoveAfterDelay, whereTask.Delay(3000, cts.Token)readsTokenon a disposed source and throwsObjectDisposedException. That escapes theOperationCanceledExceptioncatch and becomes an unobserved exception on this fire-and-forget task. SinceShowis explicitly allowed off the renderer thread, this is reachable.Capture the token before scheduling (or guard the
Tokenaccess).🛡️ Suggested guard
_ = InvokeAsync(() => { _toasts.Add(item); StateHasChanged(); - _ = RemoveAfterDelay(item.Id, cts); + if (!cts.IsCancellationRequested) + _ = RemoveAfterDelay(item.Id, cts); });Alternatively, in
RemoveAfterDelayreadcts.Tokenonce before thetry, or catchObjectDisposedExceptionaround the delay.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razor.cs` around lines 27 - 49, `BitFcCalendarToast.Show`/`RemoveAfterDelay` has a disposal race where `cts.Token` can be accessed after `DisposeAsync` disposes the `CancellationTokenSource`, causing `ObjectDisposedException` before the existing `OperationCanceledException` handling. Fix this by capturing the cancellation token before queuing `RemoveAfterDelay` inside the `InvokeAsync` callback, or by reading `cts.Token` once at the start of `RemoveAfterDelay` and using that captured token for `Task.Delay`, with a guard for disposed sources if needed.
🧹 Nitpick comments (2)
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razor.cs (1)
197-216: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick winClone the old event before mutating state.
State.UpdateEvent(updated)runs beforeOldEventis cloned, so the change payload depends on whetherUpdateEventreplaces or mutates the existing event instance. Capture the old clone first.Proposed fix
var b = _resizeBaseEvent; + var oldEvent = BitFullCalendarChangeNotifier.CloneEvent(b); var updated = new BitFullCalendarEvent { Id = b.Id, @@ State.UpdateEvent(updated); await Notifier.NotifyAsync(new BitFullCalendarChangeEventArgs { Event = BitFullCalendarChangeNotifier.CloneEvent(updated), - OldEvent = BitFullCalendarChangeNotifier.CloneEvent(b), + OldEvent = oldEvent, Kind = BitFullCalendarChangeKind.Edit, Source = BitFullCalendarChangeSource.Resize });🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razor.cs` around lines 197 - 216, Clone the previous event state before calling State.UpdateEvent in BitFcTimelineEventBlock’s resize flow, because the OldEvent payload in BitFullCalendarChangeEventArgs should not depend on whether UpdateEvent mutates or replaces the existing instance. In the block that builds the updated BitFullCalendarEvent from _resizeBaseEvent, capture BitFullCalendarChangeNotifier.CloneEvent(b) into a local old snapshot first, then update state and use that saved clone when setting OldEvent in the notifier payload.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarTexts.cs (1)
47-51: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winRename these members to match their new semantics.
These are full composite format strings now, but the public names still read as
Prefix/Suffix. Renaming them toEventListTitleFormat,EventListCountFormat, andMoreEventsFormatwould make the API much clearer before it ships.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarTexts.cs` around lines 47 - 51, Rename the composite format string properties in BitFullCalendarTexts to reflect their new semantics: EventListTitlePrefix, EventListCountSuffix, and MoreEventsSuffix should become EventListTitleFormat, EventListCountFormat, and MoreEventsFormat. Update any references in the FullCalendar text model and related consumers so the new names match the actual full format-string behavior and the API stays clear.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.scss`:
- Around line 705-712: The current-time dot in bit-bfc-timeline-dot uses a
physical left margin, which breaks centering when the timegrid switches to RTL.
Update the styling in BitFullCalendar.scss so the dot uses a logical margin
offset instead of margin-left, and align it with the existing RTL handling used
by the label so it stays centered in both directions.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razor.cs`:
- Around line 121-126: The meridiem check in OnMeridiemChanged is using a
hardcoded Ordinal तुलना against "PM", which breaks when the component’s
culture-specific display value differs from that literal. Update the handler to
compare against CultureInfo-aware AM/PM designators (using the component’s
Culture or current culture), or normalize the select values so they always emit
invariant "AM"/"PM" strings that ConvertTo24Hour can consume consistently.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorScheme.cs`:
- Around line 55-60: The GetLabel method in BitFullCalendarColorScheme is
returning the raw colorId as a fallback, so unknown or whitespace-padded values
are not normalized. Update GetLabel to trim the fallback label before returning
it, and keep the existing behavior of using opt.Title when Find(colorId) returns
a valid title so the resolver consistently outputs a cleaned label.
---
Duplicate comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razor.cs`:
- Around line 27-49: `BitFcCalendarToast.Show`/`RemoveAfterDelay` has a disposal
race where `cts.Token` can be accessed after `DisposeAsync` disposes the
`CancellationTokenSource`, causing `ObjectDisposedException` before the existing
`OperationCanceledException` handling. Fix this by capturing the cancellation
token before queuing `RemoveAfterDelay` inside the `InvokeAsync` callback, or by
reading `cts.Token` once at the start of `RemoveAfterDelay` and using that
captured token for `Task.Delay`, with a guard for disposed sources if needed.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.scss`:
- Line 3: The remaining lint issue is in the partial import within
BitFullCalendar.scss: the `@import` still includes the .scss extension, violating
scss/load-partial-extension. Update the import statement in the FullCalendar
stylesheet to reference the shared functions partial without the extension, and
keep the existing path structure otherwise unchanged.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cs`:
- Around line 8-9: The BitFullCalendarEvent model still allows invalid date
ranges because EndDate can be set earlier than StartDate, which breaks Duration
and downstream layout logic. Enforce the invariant at the model boundary by
validating or normalizing in BitFullCalendarEvent’s StartDate/EndDate setters or
constructor so EndDate is always greater than or equal to StartDate, and make
sure Duration and any range-dependent members rely on this guaranteed ordering.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razor.cs`:
- Around line 114-125: Guard the time-grid scroll interop in
BitFcCalendarDayView.OnAfterRenderAsync against transient JS lifecycle failures,
since TryScrollToStartOfDayAsync can throw during prerender/disconnect/teardown
and currently breaks the render path. Mirror the error-handling pattern used in
BitFcAgendaEvents.razor.cs by wrapping the await in a try/catch, swallowing or
logging the expected JS failure, and only updating _timeGridScrollSignature when
the scroll call succeeds. Keep the existing BuildTimeGridScrollSignature and
_timeGridScrollSignature logic unchanged aside from advancing the signature
after a successful interop call.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razor.cs`:
- Around line 99-110: The week-view render path in OnAfterRenderAsync should
guard the awaited BitFcTimeGridScrollInterop.TryScrollToStartOfDayAsync call
against transient JS failures, just like the agenda view. Wrap the interop call
in a transient-exception-safe pattern, and only assign _timeGridScrollSignature
after a successful scroll; use the existing identifiers OnAfterRenderAsync,
BitFcTimeGridScrollInterop.TryScrollToStartOfDayAsync, and
_timeGridScrollSignature to make the fix consistent with the other view.
In `@src/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scss`:
- Line 7: The FullCalendar import in extra-components.scss should follow the
same partial-import style as the other SCSS imports. Update the `@import`
statement that references BitFullCalendar to omit the .scss extension so it
matches the existing load-partial-extension convention and stays consistent with
the other partial imports in this stylesheet.
In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razor`:
- Around line 113-146: The FullCalendar demo allows unsupported view/mode
combinations because BitFullCalendarDemo.razor binds all
BitChoiceGroupOption<BitFullCalendarView> values even when bindingMode is
BitFullCalendarMode.Timeline. Update the demo logic in the view/mode handlers
(HandleModeChange and/or HandleViewChange) to either hide/disable Year and
Agenda in Timeline mode or automatically coerce bindingView to a supported
BitFullCalendarView when bindingMode changes. Also keep the mirrored example
text in example7RazorCode aligned with this supported timeline behavior.
---
Nitpick comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarTexts.cs`:
- Around line 47-51: Rename the composite format string properties in
BitFullCalendarTexts to reflect their new semantics: EventListTitlePrefix,
EventListCountSuffix, and MoreEventsSuffix should become EventListTitleFormat,
EventListCountFormat, and MoreEventsFormat. Update any references in the
FullCalendar text model and related consumers so the new names match the actual
full format-string behavior and the API stays clear.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razor.cs`:
- Around line 197-216: Clone the previous event state before calling
State.UpdateEvent in BitFcTimelineEventBlock’s resize flow, because the OldEvent
payload in BitFullCalendarChangeEventArgs should not depend on whether
UpdateEvent mutates or replaces the existing instance. In the block that builds
the updated BitFullCalendarEvent from _resizeBaseEvent, capture
BitFullCalendarChangeNotifier.CloneEvent(b) into a local old snapshot first,
then update state and use that saved clone when setting OldEvent in the notifier
payload.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: fee8b6a5-c2ac-4057-9033-4c1af828ecff
📒 Files selected for processing (101)
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarBody.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarBody.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.scsssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcAddEditEventDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcAddEditEventDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventDetailsDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventDetailsDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarAgendaGroupBy.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarBadgeVariant.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarEventLayout.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarMode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarView.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcDateNavigator.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcDateNavigator.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcFilterEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcFilterEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcTodayButton.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcTodayButton.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcViewTabs.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcViewTabs.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarAttendee.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarCell.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarChangeEventArgs.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorOption.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorScheme.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarDateChangeEventArgs.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarResource.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarSettings.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarTexts.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcAgendaScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcDialogInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcTimeGridScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcTimelineScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarChangeNotifier.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarHelpers.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarState.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcDayViewMultiDayEventsRow.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcDayViewMultiDayEventsRow.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcRenderGroupedEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcRenderGroupedEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcTimeColumn.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcTimeColumn.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcCalendarMonthView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcCalendarMonthView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcDayCell.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcDayCell.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcEventBullet.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcEventBullet.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcMonthEventBadge.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcMonthEventBadge.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineLayout.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineLayout.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scsssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razor.cssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/ComponentsSection.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/MainLayout.razor.NavItems.cs
| .bit-bfc-timeline-dot { | ||
| width: 10px; | ||
| height: 10px; | ||
| border-radius: 50%; | ||
| background: var(--bit-bfc-timeline-color); | ||
| margin-left: -5px; | ||
| flex-shrink: 0; | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Use a logical margin so the current-time dot stays centered in RTL.
The timegrid flips to direction: rtl, so the dot moves to the leading (right) edge, but margin-left: -5px then offsets it on the wrong side. The label already has an RTL override; the dot should follow with a logical margin.
Suggested fix
.bit-bfc-timeline-dot {
width: 10px;
height: 10px;
border-radius: 50%;
background: var(--bit-bfc-timeline-color);
- margin-left: -5px;
+ margin-inline-start: -5px;
flex-shrink: 0;
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| .bit-bfc-timeline-dot { | |
| width: 10px; | |
| height: 10px; | |
| border-radius: 50%; | |
| background: var(--bit-bfc-timeline-color); | |
| margin-left: -5px; | |
| flex-shrink: 0; | |
| } | |
| .bit-bfc-timeline-dot { | |
| width: 10px; | |
| height: 10px; | |
| border-radius: 50%; | |
| background: var(--bit-bfc-timeline-color); | |
| margin-inline-start: -5px; | |
| flex-shrink: 0; | |
| } |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.scss`
around lines 705 - 712, The current-time dot in bit-bfc-timeline-dot uses a
physical left margin, which breaks centering when the timegrid switches to RTL.
Update the styling in BitFullCalendar.scss so the dot uses a logical margin
offset instead of margin-left, and align it with the existing RTL handling used
by the label so it stays centered in both directions.
| private async Task OnMeridiemChanged(ChangeEventArgs e) | ||
| { | ||
| var pm = string.Equals(e.Value?.ToString(), "PM", StringComparison.Ordinal); | ||
| _hour = ConvertTo24Hour(Hour12, pm); | ||
| await OnTimeChanged(); | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Inspect how the meridiem <select> options are rendered in the picker markup.
rg -nP -C3 'OnMeridiemChanged|AMPMDesignator|>AM<|>PM<|IsPm|Meridiem' \
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razorRepository: bitfoundation/bitplatform
Length of output: 2002
The meridiem comparison logic is fragile and will fail for non-invariant cultures.
The OnMeridiemChanged handler performs a strict StringComparison.Ordinal check against the literal "PM". However, the component renders time using Culture-specific formatting ("h:mm tt"), which implies the UI dropdown options will display the culture's specific PM designator (e.g., "p.m.", "PM", or localized equivalents like "ب.ظ"). If the running culture's designator differs from the literal string "PM", the comparison will fail, causing the hour conversion to ConvertTo24Hour to be skipped.
Update the comparison to use CultureInfo-aware logic or ensure the select options explicitly use invariant "AM"/"PM" string values that match the backend:
// Option 1: Culture-aware check (Recommended)
var culture = CultureInfo.CurrentCulture;
var pmDesignator = culture.DateTimeFormat.PMDesignator;
var isPm = string.Equals(e.Value?.ToString(), pmDesignator, culture.StringComparison);
// Option 2: Invariant normalization (if UI is forced to use AM/PM)
var isPm = string.Equals(e.Value?.ToString()?.Trim(), "PM", StringComparison.OrdinalIgnoreCase)
|| string.Equals(e.Value?.ToString()?.Trim(), culture.DateTimeFormat.PMDesignator, culture.StringComparison);🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razor.cs`
around lines 121 - 126, The meridiem check in OnMeridiemChanged is using a
hardcoded Ordinal तुलना against "PM", which breaks when the component’s
culture-specific display value differs from that literal. Update the handler to
compare against CultureInfo-aware AM/PM designators (using the component’s
Culture or current culture), or normalize the select values so they always emit
invariant "AM"/"PM" strings that ConvertTo24Hour can consume consistently.
| public string GetLabel(string? colorId) | ||
| { | ||
| var opt = Find(colorId); | ||
| if (opt is not null && !string.IsNullOrWhiteSpace(opt.Title)) | ||
| return opt.Title; | ||
| return colorId ?? string.Empty; |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Trim the fallback label.
Line 60 returns the raw colorId, so unknown values like " blue " or whitespace-only strings render with padding instead of the normalized label the rest of the resolver uses.
Suggested fix
public string GetLabel(string? colorId)
{
var opt = Find(colorId);
if (opt is not null && !string.IsNullOrWhiteSpace(opt.Title))
return opt.Title;
- return colorId ?? string.Empty;
+ return colorId?.Trim() ?? string.Empty;
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| public string GetLabel(string? colorId) | |
| { | |
| var opt = Find(colorId); | |
| if (opt is not null && !string.IsNullOrWhiteSpace(opt.Title)) | |
| return opt.Title; | |
| return colorId ?? string.Empty; | |
| public string GetLabel(string? colorId) | |
| { | |
| var opt = Find(colorId); | |
| if (opt is not null && !string.IsNullOrWhiteSpace(opt.Title)) | |
| return opt.Title; | |
| return colorId?.Trim() ?? string.Empty; |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorScheme.cs`
around lines 55 - 60, The GetLabel method in BitFullCalendarColorScheme is
returning the raw colorId as a fallback, so unknown or whitespace-padded values
are not normalized. Update GetLabel to trim the fallback label before returning
it, and keep the existing behavior of using opt.Title when Find(colorId) returns
a valid title so the resolver consistently outputs a cleaned label.
closes #12449
Summary by CodeRabbit
BitFullCalendar, including Month/Week/Day/Year/Agenda views plus resource-based Event ⇄ Timeline mode, RTL support, and culture-aware navigation/labels./components/fullcalendardemo with localization and render-template examples.BitFullCalendartheming with responsive and RTL visuals.